Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2026
Warning: Invalid argument supplied for foreach() in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2026
Warning: Invalid argument supplied for foreach() in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2398
Warning: implode() [function.implode]: Argument must be an array in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3351
Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3374
Warning: Invalid argument supplied for foreach() in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3374
Warning: Invalid argument supplied for foreach() in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3415
Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3467
Warning: Invalid argument supplied for foreach() in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3467
Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3612
Warning: Invalid argument supplied for foreach() in /home/viricmin/labs/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3612
Actualmente trabajo de becario (programador) modificando algunos programas escritos en Java (que funcionarán sobre OpenJDK) y debido a las tareas que me encargan me acabé preguntando sobre el rendimiento en el tratamiento de cadenas. Buscando por internet encontré este artículo [1] que aclaró bastante las cosas. Yo lo voy a reescribir aquí por si algún día desaparece ese artículo, además voy a fijarme en algún otro aspecto no comentado allí.
En Java podemos encontrar tres clases diferentes que nos permiten trabajar con cadenas, la archiconocida String, StringBuffer y StringBuilder. Debido a que los objetos String son inmutables, cada vez que se hace una concatenación con el operador + se debe crear un nuevo objeto que albergue el resultado (y en caso de que las cadenas anteriores no esten referenciadas, eliminar los objetos correspondientes). Por eso también existe la clase StringBuffer que nos permite añadir a la cadena que contiene otras cadenas con su método append sin tener que construir ni destruir ningún objeto. Con ello se consigue una mejora de rendimiento considerable cuando se hacen muchas concatenaciones, luego si se quiere trabajar con un objeto String solo tenemos que usar el método toString y listos.
La clase StringBuffer está diseñada para ser segura en un entorno concurrente, por lo que tiene código extra para gestionar los bloqueos y demás. Esta característica no siempre nos es útil y puede hacer decrecer el rendimiento en demasía, por lo que también se creó la clase StringBuilder que no es segura para operaciones concurrentes pero puede ser el doble de rápida que StringBuffer (además, casi siempre que trabajamos con cadenas es de forma no concurrente).
Tanto StringBuffer como StringBuilder escalan linealmente a medida que aumentamos el número de concatenaciones, no siendo así en el caso de la clase String que parece mostrar un incremento supralineal en el consumo de recursos. Aquí os dejo las tablas de resultados, para String no están completas porque tardaba demasiado y me he cansado.
run: StringBuffer (100): 0 StringBuffer (1000): 3 StringBuffer (10000): 19 StringBuffer (100000): 13 StringBuffer (1000000): 75 StringBuffer (10000000): 642 StringBuffer (50000000): 2738 StringBuilder (100): 0 StringBuilder (1000): 0 StringBuilder (10000): 4 StringBuilder (100000): 70 StringBuilder (1000000): 32 StringBuilder (10000000): 342 StringBuilder (50000000): 1706 String (100): 1 String (1000): 67 String (10000): 777 String (100000): 80040
Los números indican la cantidad de milisegundos consumidos para la cantidad indicada de concatenaciones. El código que he usado es éste:
public static void main(String[] args) { // StringBuffer System.out.println("StringBuffer (100): "+cSBuffer(100)); System.out.println("StringBuffer (1000): "+cSBuffer(1000)); System.out.println("StringBuffer (10000): "+cSBuffer(10000)); System.out.println("StringBuffer (100000): "+cSBuffer(100000)); System.out.println("StringBuffer (1000000): "+cSBuffer(1000000)); System.out.println("StringBuffer (10000000): "+cSBuffer(10000000)); System.out.println("StringBuffer (50000000): "+cSBuffer(50000000)); // END StringBuffer System.out.println(); // StringBuilder System.out.println("StringBuilder (100): "+cSBuilder(100)); System.out.println("StringBuilder (1000): "+cSBuilder(1000)); System.out.println("StringBuilder (10000): "+cSBuilder(10000)); System.out.println("StringBuilder (100000): "+cSBuilder(100000)); System.out.println("StringBuilder (1000000): "+cSBuilder(1000000)); System.out.println("StringBuilder (10000000): "+cSBuilder(10000000)); System.out.println("StringBuilder (50000000): "+cSBuilder(50000000)); // END StringBuilder System.out.println(); // StringBuilder System.out.println("String (100): "+cS(100)); System.out.println("String (1000): "+cS(1000)); System.out.println("String (10000): "+cS(10000)); System.out.println("String (100000): "+cS(100000)); System.out.println("String (1000000): "+cS(1000000)); System.out.println("String (10000000): "+cS(10000000)); System.out.println("String (50000000): "+cS(50000000)); // END StringBuilder } static private long cSBuffer(long num) { long ini = System.currentTimeMillis(); StringBuffer sbuffer = new StringBuffer(); for(int i=0; i
Por cierto, y esto tiene poco que ver con lo de las clases. Lo he probado con IKVM también... y bueno, tengo que decir que va el doble de lento que con OpenJDK (no lo he probado con la máquina Hotspot de Sun).