studio reales proyectos programacion libro introducción incluye herramientas fundamentos fuente español código con avanzado aplicaciones java performance string garbage-collection

java - reales - ¿Qué ciclo tiene un mejor rendimiento? ¿Por qué?



libro de android studio en español pdf (8)

String s = ""; for(i=0;i<....){ s = some Assignment; }

o

for(i=0;i<..){ String s = some Assignment; }

No necesito usar "s" fuera del ciclo nunca más. La primera opción es quizás mejor ya que una nueva Cadena no se inicializa cada vez. Sin embargo, el segundo resultaría en que el alcance de la variable se limite al bucle mismo.

EDITAR: En respuesta a la respuesta de Milhous. Sería inútil asignar el String a una constante dentro de un bucle ¿no? No, aquí ''alguna Asignación'' significa un valor cambiante obtenido de la lista que se itera.

Además, la pregunta no es porque me preocupe la administración de la memoria. Solo quiero saber que es mejor.


Alcance limitado es el mejor

Usa tu segunda opción:

for ( ... ) { String s = ...; }

El alcance no afecta el rendimiento

Si desensambla el código compilado de cada uno (con la herramienta javap del JDK), verá que el bucle compila exactamente las mismas instrucciones JVM en ambos casos. Tenga en cuenta también que la "Opción n.º 3" de Brian R. Bondy es idéntica a la Opción n.º 1. Nada extra se agrega o elimina de la pila cuando se utiliza el alcance más estricto, y los mismos datos se utilizan en la pila en ambos casos.

Evitar la inicialización prematura

La única diferencia entre los dos casos es que, en el primer ejemplo, la variable s se inicializa innecesariamente. Este es un problema separado de la ubicación de la declaración de variable. Esto agrega dos instrucciones desperdiciadas (para cargar una constante de cadena y almacenarla en una ranura de marco de pila). Una buena herramienta de análisis estático le advertirá que nunca lee el valor que asigna a s , y un buen compilador de JIT probablemente lo omitirá en el tiempo de ejecución.

Puede solucionar esto simplemente usando una declaración vacía (es decir, String s; ), pero esto se considera una mala práctica y tiene otro efecto secundario que se analiza a continuación.

A menudo, un valor falso como null se asigna a una variable simplemente para silenciar un error del compilador de que una variable se lee sin inicializarse. Este error puede tomarse como una sugerencia de que el alcance de la variable es demasiado grande y de que se declara antes de que sea necesario para recibir un valor válido. Las declaraciones vacías lo obligan a considerar cada ruta de código; no ignore esta valiosa advertencia asignando un valor falso.

Conservar ranuras de pila

Como se mencionó, aunque las instrucciones de JVM son las mismas en ambos casos, existe un sutil efecto secundario que hace que sea mejor, a nivel de JVM, utilizar el alcance más limitado posible. Esto es visible en la "tabla de variables locales" para el método. Considere lo que sucede si tiene múltiples bucles, con las variables declaradas en un alcance innecesariamente grande:

void x(String[] strings, Integer[] integers) { String s; for (int i = 0; i < strings.length; ++i) { s = strings[0]; ... } Integer n; for (int i = 0; i < integers.length; ++i) { n = integers[i]; ... } }

Las variables s y n podrían declararse dentro de sus respectivos bucles, pero como no lo son, el compilador usa dos "ranuras" en el marco de la pila. Si se declararon dentro del ciclo, el compilador puede reutilizar la misma ranura, reduciendo el marco de la pila.

Lo que realmente importa

Sin embargo, la mayoría de estos problemas son inmateriales. Un buen compilador JIT verá que no es posible leer el valor inicial que está asignando inútilmente y optimizar la asignación. Guardar una ranura aquí o allá no va a hacer o deshacer su aplicación.

Lo importante es hacer que su código sea legible y fácil de mantener, y en ese sentido, usar un alcance limitado es claramente mejor. Cuanto menor sea el alcance de una variable, más fácil será comprender cómo se usa y qué impacto tendrán los cambios en el código.


Cuando estoy usando varios hilos (más de 50), creo que esta es una forma muy efectiva de manejar problemas de hilos fantasma al no poder cerrar un proceso correctamente ... si me equivoco, por favor díganme por qué Me equivoco:

Process one; BufferedInputStream two; try{ one = Runtime.getRuntime().exec(command); two = new BufferedInputStream(one.getInputStream()); } }catch(e){ e.printstacktrace } finally{ //null to ensure they are erased one = null; two = null; //nudge the gc System.gc(); }


En teoría , es un desperdicio de recursos declarar la cadena dentro del ciclo. En la práctica , sin embargo, los dos fragmentos que presentó se compilarán hasta el mismo código (declaración fuera del ciclo).

Entonces, si su compilador realiza cualquier cantidad de optimización, no hay diferencia.


En general, elegiría el segundo, porque el alcance de la variable ''s'' está limitado al ciclo. Beneficios:

  • Esto es mejor para el programador porque no tiene que preocuparse porque ''s'' se use nuevamente en algún momento posterior de la función
  • Esto es mejor para el compilador porque el alcance de la variable es más pequeño, por lo que potencialmente puede hacer más análisis y optimización.
  • Esto es mejor para los lectores futuros porque no se preguntarán por qué la variable ''s'' se declara fuera del ciclo si nunca se usa más tarde.

Me parece que necesitamos más especificaciones del problema.

los

s = some Assignment;

no se especifica en qué tipo de asignación se trata. Si la tarea es

s = "" + i + "";

entonces se necesita asignar un nuevo aguijón.

pero si es

s = some Constant;

s simplemente señalará la ubicación de la memoria de las constantes, y por lo tanto la primera versión sería más eficiente con la memoria.

Parece un poco tonto preocuparse por la optimización de un bucle for para un idioma interpretado en mi humilde opinión.


Para agregar un poco a la respuesta de @ Esteban Araya , ambos requerirán la creación de una nueva cadena cada vez a través del ciclo (como el valor de retorno de la expresión de some Assignment ). Esas cadenas deben ser recogidas de basura de cualquier manera.


Sé que esta es una vieja pregunta, pero pensé que agregaría algo que está ligeramente relacionado.

Al navegar por el código fuente de Java, me di cuenta de que algunos métodos, como String.contentEquals (duplicado a continuación), generan variables locales redundantes que son simplemente copias de variables de clase. Creo que hubo un comentario en alguna parte, que implicaba que acceder a las variables locales es más rápido que acceder a las variables de clase.

En este caso, "v1" y "v2" son aparentemente innecesarios y podrían eliminarse para simplificar el código, pero se agregaron para mejorar el rendimiento.

public boolean contentEquals(StringBuffer sb) { synchronized(sb) { if (count != sb.length()) return false; char v1[] = value; char v2[] = sb.getValue(); int i = offset; int j = 0; int n = count; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } } return true; }


Si desea acelerar los bucles, prefiero declarar una variable máxima al lado del contador para que no se necesiten búsquedas repetidas para la condición:

en lugar de

for (int i = 0; i < array.length; i++) { Object next = array[i]; }

yo prefiero

for (int i = 0, max = array.lenth; i < max; i++) { Object next = array[i]; }

Cualquier otra cosa que deba considerarse ya ha sido mencionada, así que solo mis dos centavos (vea la publicación de ericksons)

Greetz, GHad