¿El uso de final for variables en Java mejora la recolección de basura?


Hoy mis colegas y yo tenemos una discusión sobre el uso de la palabra clave final en Java para mejorar la recolección de basura.

Por ejemplo, si escribes un método como:

public Double doCalc(final Double value)
{
   final Double maxWeight = 1000.0;
   final Double totalWeight = maxWeight * value;
   return totalWeight;  
}

Declarar las variables en el método final ayudaría a la recolección de basura a limpiar la memoria de las variables no utilizadas en el método después de que el método salga.

¿Es esto cierto?

Author: Goran Martinic, 2008-11-21

14 answers

Aquí hay un ejemplo ligeramente diferente, uno con campos de tipo de referencia final en lugar de variables locales de tipo de valor final:

public class MyClass {

   public final MyOtherObject obj;

}

Cada vez que cree una instancia de MyClass, estará creando una referencia saliente a una instancia de MyOtherObject, y el GC tendrá que seguir ese enlace para buscar objetos en vivo.

La JVM utiliza un algoritmo GC de barrido de marcas, que tiene que examinar todas las referencias en vivo en las ubicaciones "raíz" de GC (como todos los objetos en la llamada actual pila). Cada objeto vivo es "marcado" como vivo, y cualquier objeto referido por un objeto vivo también es marcado como vivo.

Después de la finalización de la fase de marcado, el GC barre a través del montón, liberando memoria para todos los objetos sin marcar (y compactando la memoria para los objetos vivos restantes).

Además, es importante reconocer que la memoria del montón de Java está dividida en una "generación joven" y una "generación vieja". Todos los objetos se asignan inicialmente en el joven generación (a veces referido como "el vivero"). Dado que la mayoría de los objetos son de corta duración, el GC es más agresivo sobre la liberación de la basura reciente de la generación joven. Si un objeto sobrevive a un ciclo de colección de la generación joven, se traslada a la generación antigua (a veces conocida como la "generación titular"), que se procesa con menos frecuencia.

Así que, en la parte superior de mi cabeza, voy a decir "no, el modificador 'final' no ayuda al GC a reducir su carga de trabajo".

En mi opinión, la mejor estrategia para optimizar su gestión de memoria en Java es eliminar las referencias falsas lo más rápido posible. Podría hacerlo asignando "null" a una referencia de objeto tan pronto como haya terminado de usarla.

O, mejor aún, minimizar el tamaño de cada ámbito de declaración. Por ejemplo, si declara un objeto al principio de un método de 1000 líneas, y si el objeto permanece vivo hasta el cierre del ámbito de ese método (el último cierre rizado brace), entonces el objeto podría permanecer vivo por mucho más tiempo que realmente necesario.

Si utiliza métodos pequeños, con solo una docena de líneas de código, entonces los objetos declarados dentro de ese método caerán fuera de alcance más rápidamente, y el GC será capaz de hacer la mayor parte de su trabajo dentro de la generación joven mucho más eficiente. No quieres que los objetos se trasladen a la generación anterior a menos que sea absolutamente necesario.

 80
Author: benjismith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-20 21:46:09

Declarar una variable local final no afectará la recolección de basura, solo significa que no puede modificar la variable. El ejemplo anterior no debería compilarse ya que está modificando la variable totalWeight que ha sido marcada final. Por otro lado, declarando un primitivo (double en lugar de Double) final will permite que esa variable se inserte en el código de llamada, por lo que podría causar alguna mejora de la memoria y el rendimiento. Esto se utiliza cuando se tiene un número de public static final Strings en un clase.

En general, el compilador y el tiempo de ejecución optimizarán donde puedan. Lo mejor es escribir el código apropiadamente y no tratar de ser demasiado complicado. Utilice final cuando no desee que se modifique la variable. Suponga que cualquier optimización fácil será realizada por el compilador, y si le preocupa el rendimiento o el uso de memoria, use un generador de perfiles para determinar el problema real.

 37
Author: Aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-21 02:38:12

No, enfáticamente no es verdad.

Recuerde que final no significa constante, solo significa que no puede cambiar la referencia.

final MyObject o = new MyObject();
o.setValue("foo"); // Works just fine
o = new MyObject(); // Doesn't work.

Puede haber alguna pequeña optimización basada en el conocimiento de que la JVM nunca tendrá que modificar la referencia (como no tener que verificar si ha cambiado), pero sería tan pequeña como para no preocuparse.

Final debe considerarse como meta-datos útiles para el desarrollador y no como una optimización del compilador.

 24
Author: SCdF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-20 21:23:36

Algunos puntos para aclarar:

  • Nulling out reference should not help GC. Si lo hiciera, indicaría que sus variables están sobre scoped. Una excepción es el caso del nepotismo de objetos.

  • Todavía no hay asignación en la pila en Java.

  • Declarar una variable final significa que no puede (en condiciones normales) asignar un nuevo valor a esa variable. Desde final no dice nada sobre el alcance, no dice nada sobre su efecto en GC.

 15
Author: Kirk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-20 15:50:49

Bueno, no se sobre el uso del modificador "final" en este caso, o su efecto en el GC.

Pero yo puedo decirle esto: su uso de valores en caja en lugar de primitivos (por ejemplo, Doble en lugar de doble) asignará esos objetos en el montón en lugar de la pila, y producirá basura innecesaria que el GC tendrá que limpiar.

Solo uso primitivas en caja cuando lo requiere una API existente, o cuando necesito primativas nullables.

 11
Author: benjismith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-20 21:13:29

Las variables finales no se pueden cambiar después de la asignación inicial (forzada por el compilador).

Esto no cambia el comportamiento de la colección de basura como tal. Lo único es que estas variables no pueden ser anuladas cuando ya no se utilizan (lo que puede ayudar a la recolección de basura en situaciones de falta de memoria).

Debe saber que final permite al compilador hacer suposiciones sobre qué optimizar. Código en línea y sin incluir código conocido por no ser accesible.

final boolean debug = false;

......

if (debug) {
  System.out.println("DEBUG INFO!");
}

El println no se incluirá en el código de bytes.

 5
Author: Thorbjørn Ravn Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-30 08:16:29

GC actúa sobre referencias inalcanzables. Esto no tiene nada que ver con "final", que es simplemente una afirmación de asignación de una sola vez. ¿Es posible que algún GC de VM pueda hacer uso de"final"? No veo cómo ni por qué.

 3
Author: dongilmore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-20 21:56:43

Hay un caso de esquina no tan conocido con los recolectores de basura generacionales. (Para una breve descripción lea la respuesta de benjismith para una visión más profunda lea los artículos al final).

La idea en las ECG generacionales es que la mayoría de las veces solo las generaciones jóvenes necesitan ser consideradas. La ubicación raíz se analiza en busca de referencias y, a continuación, se analizan los objetos de la generación joven. Durante estos barridos más frecuentes ningún objeto en la vieja generación son comprobar.

Ahora, el problema viene del hecho de que a un objeto no se le permite tener referencias a objetos más jóvenes. Cuando un objeto de larga vida (generación antigua) obtiene una referencia a un objeto nuevo, esa referencia debe ser rastreada explícitamente por el recolector de basura (consulte el artículo de IBM sobre el recopilador JVM de punto de acceso ), afectando realmente el rendimiento de GC.

La razón por la que un objeto antiguo no puede referirse a uno más joven es que, como el objeto antiguo no está marcado en menor colecciones, si la única referencia al objeto se mantiene en el objeto antiguo, no se marcará, y se desasignará erróneamente durante la etapa de barrido.

Por supuesto, como han señalado muchos, la palabra clave final no afecta realmente al recolector de basura, pero garantiza que la referencia nunca se cambiará a un objeto más joven si este objeto sobrevive a las colecciones menores y llega al montón más antiguo.

Artículos:

IBM en la recolección de basura: history , en el hotspot JVM y performance . Es posible que ya no sean plenamente válidas, ya que se remontan a 2003/04, pero proporcionan una visión fácil de leer de las ECM.

Sun on Tuning garbage collection

 3
Author: David Rodríguez - dribeas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:49

final en las variables y parámetros locales no hace ninguna diferencia con los archivos de clase producidos, por lo que no puede afectar el rendimiento del tiempo de ejecución. Si una clase no tiene subclases, HotSpot trata esa clase como si fuera final de todos modos (puede deshacer más tarde si se carga una clase que rompe esa suposición). Creo que final en métodos es lo mismo que en clases. final en el campo estático puede permitir que la variable se interprete como una "constante en tiempo de compilación" y que javac realice la optimización sobre esa base. final el fields permite a la JVM cierta libertad para ignorar sucede-antes de relaciones.

 3
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-25 18:16:03

Parece que hay muchas respuestas que son conjeturas errantes. La verdad es que no hay un modificador final para las variables locales a nivel de bytecode. La máquina virtual nunca sabrá que sus variables locales se definieron como finales o no.

La respuesta a tu pregunta es un rotundo no.

 2
Author: Matt Quigley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-17 18:52:38

Todos los métodos y variables pueden ser sobrescritos por default en subclases.Si queremos guardar las subclases de sobrescribir los miembros de superclass, podemos declararlas como finales usando la palabra clave final. Por ejemplo:- final int a=10; final void display(){......} Hacer un método final asegura que la funcionalidad definida en la superclase nunca se cambiará de todos modos. Del mismo modo, el valor de una variable final nunca se puede cambiar. Las variables finales se comportan como variables de clase.

 1
Author: Debasish Pakhira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-07 21:10:59

Lo único que se me ocurre es que el compilador podría optimizar las variables finales e insertarlas como constantes en el código, por lo que terminas sin memoria asignada.

 0
Author: Sijin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-20 21:21:52

Absolutamente, siempre y cuando acortar la vida del objeto que producen un gran beneficio de la gestión de memoria, recientemente examinamos la funcionalidad de exportación que tiene variables de instancia en una prueba y otra prueba que tiene variable local a nivel de método. durante la prueba de carga, JVM lanza el error de memoria en la primera prueba y JVM se detuvo. pero en la segunda prueba, con éxito capaz de obtener el informe debido a una mejor gestión de la memoria.

 0
Author: santhosh kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-27 18:05:38

La única vez que prefiero declarar variables locales como finales es cuando:

  • Yo tengo para hacerlos finales para que puedan ser compartidos con alguna clase anónima (por ejemplo: crear un hilo demonio y permitirle acceder a algún valor desde el método de encerramiento)

  • I want to make them final (for example: some value that shouldn't/doesn't get overridden by mistake)

¿Ayudan en la basura rápida colección?
AFAIK un objeto se convierte en un candidato de la colección GC si tiene cero referencias fuertes a él y en ese caso también no hay garantía de que serán recogidos inmediatamente basura . En general, se dice que una referencia fuerte muere cuando sale de alcance o el usuario lo reasigna explícitamente a referencia nula, por lo tanto, declararlos finales significa que la referencia continuará existiendo hasta que exista el método (a menos que su alcance se reduzca explícitamente a una referencia interna específica block {}) porque no se pueden reasignar las variables finales. Así que creo que w.r. t Recolección de basura 'final' puede introducir un posible retraso no deseado.

 0
Author: sactiw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-17 09:57:37