java - ser - recolección de residuos
¿El objeto no utilizado está disponible para la recolección de basura cuando todavía está visible en la pila? (5)
en primer lugar, la cadena "s1" está claramente disponible para la recolección de basura antes de la declaración de retorno
No está claro en absoluto. Creo que estás confundiendo "no utilizado" con "inalcanzable". No son necesariamente lo mismo.
Hablando formalmente, la variable está activa hasta que finaliza su ámbito de cobertura, por lo que no está disponible para la recolección de basura hasta ese momento.
Sin embargo, "un compilador de Java o un generador de código puede optar por establecer una variable o un parámetro que ya no se utilizará como nulo para hacer que el almacenamiento de dicho objeto sea potencialmente reclamable antes" jls-12.6.1 .
En el siguiente ejemplo hay dos métodos funcionalmente equivalentes:
public class Question {
public static String method1() {
String s = new String("s1");
// some operations on s1
s = new String("s2");
return s;
}
public static String method2() {
final String s1 = new String("s1");
// some operations on s1
final String s2 = new String("s2");
return s2;
}
}
sin embargo, en el primero ( method1
) de ellos, la cadena "s1" está claramente disponible para la recolección de basura antes de la declaración de return
. En la segunda ( method2
), la cadena "s1" aún es accesible (aunque desde la revisión de código posible no se usa más).
Mi pregunta es: ¿hay algo en la especificación de jvm que diga que una vez que la variable no se usa en la pila, podría estar disponible para la recolección de basura?
EDITAR: A veces las variables pueden referirse a objetos como imágenes completamente renderizadas y que tienen un impacto en la memoria.
Lo pregunto por consideraciones prácticas. Tengo gran parte del código codicioso de memoria en un método y estoy pensando si podría ayudar a JVM (un poco) simplemente dividiendo este método en unos pocos pequeños.
Realmente prefiero el código donde no se realiza ninguna reasignación, ya que es más fácil de leer y razonar.
ACTUALIZACIÓN : por jls-12.6.1 :
El compilador de Java o el generador de código pueden optar por establecer una variable o parámetro que ya no se utilizará como nulo para que el almacenamiento de dicho objeto sea potencialmente reclamable antes.
Así que parece que es posible que GC reclame un objeto que aún esté visible. Sin embargo, dudo que esta optimización se realice durante la compilación fuera de línea (se estropearía la depuración) y probablemente lo hará JIT.
Básicamente, los marcos de apilamiento y el área estática son considerados como raíces por GC. Entonces, si se hace referencia al objeto desde cualquier marco de pila, se considera vivo. El problema con la recuperación de algunos objetos del marco de pila activo es que GC funciona en paralelo con la aplicación (mutador). ¿Cómo crees que GC debería descubrir que el objeto no se usa mientras el método está en progreso? Eso requeriría una sincronización que sería MUY pesada y compleja, de hecho, romperá la idea de que GC funcione en paralelo con el mutador. Cada hilo puede mantener las variables en los registros del procesador. Para implementar su lógica, también deben agregarse a las raíces de GC. Ni siquiera puedo imaginar cómo implementarlo.
Para responder a su pregunta. Si tiene alguna lógica que produzca muchos objetos que no se usen en el futuro, sepárelos en un método distinto. Esto es realmente una buena práctica.
También debe tomar optimizaciones de la cuenta int por JVM (como señaló EJP). También hay un análisis de escape, que podría evitar que el objeto se asigne a un montón. Pero confiar en el rendimiento de sus códigos es una mala práctica.
No, porque su código posiblemente podría recuperarlo y hacer algo con él, y el resumen de JVM no considera qué código está por venir. Sin embargo, una JVM optimizadora muy, muy, muy inteligente podría analizar el código a continuación y encontrar que no hay manera de que se pueda hacer referencia a s1
, y de que sea recolectada por la basura. Aunque definitivamente no puedes contar con esto.
Si está hablando del intérprete, en el segundo caso S1 permanece "referenciado" hasta que el método sale y el marco de pila se enrolla. (Es decir, en el intérprete estándar: es totalmente posible que GC use la información de vida a partir de la verificación del método. Y, además (y más probablemente), javac puede hacer su propio análisis de vida y "compartir" los espacios de los intérpretes basándose en eso. )
Sin embargo, en el caso del JITC, una optimización leve podría reconocer que S1 no está en uso y reciclar ese registro para S2. O puede que no. El GC examinará el contenido del registro, y si S1 se ha reutilizado para otra cosa, entonces se reclamará el antiguo objeto S1 (si no se hace referencia a él). Si la ubicación de S1 no se ha reutilizado, es posible que el objeto de S1 no se recupere.
"Podría no" porque, dependiendo de la JVM, el JITC puede o no proporcionar al GC un mapa de dónde están "activas" las referencias de objetos en el flujo del programa. Y este mapa, si se proporciona, puede o no puede identificar con precisión el final del "rango en vivo" (el último punto de referencia) de S1. Muchas posibilidades diferentes.
Tenga en cuenta que esta variabilidad potencial no viola ningún principio de Java: no se requiere que GC reclame un objeto lo antes posible, y no existe una forma práctica para que un programa sea sensible precisamente cuando se reclama un objeto.
VM es libre de optimizar el código para anular s1
antes de salir del método (siempre y cuando sea correcto), por lo que s1
podría ser elegible para basura antes.
Sin embargo, eso no es necesario. Muchas invocaciones de métodos deben haber ocurrido antes del siguiente CG; Todos los marcos de pila se han borrado de todos modos, no hay necesidad de preocuparse por una variable local específica en una invocación de método específica.
En cuanto a Java, el lenguaje, los basureros pueden vivir para siempre sin impacto en la semántica del programa. Es por eso que JLS apenas habla de basura.