allocate - java heap data structure
¿Qué pasa con la memoria estática en Java? (6)
Esta pregunta es para el lenguaje Java en particular. Entiendo que hay una reserva estática de memoria reservada para todos los códigos estáticos.
Mi pregunta es ¿cómo se llena esta memoria estática? ¿Se coloca un objeto estático en la memoria estática en la importación o en la primera referencia? Además, ¿se aplican las mismas reglas de recolección de basura a los objetos estáticos que a los demás objetos?
public class Example{
public static SomeObject someO = new SomeObject();
}
/********************************/
// Is the static object put into static memory at this point?
import somepackage.Example;
public class MainApp{
public static void main( Sting args[] ){
// Or is the static object put into memory at first reference?
Example.someO.someMethod();
// Do the same garbage collection rules apply to a
// static object as they do all others?
Example.someO = null;
System.gc();
}
}
Esta variable estática alguna0 se inicializa tan pronto como se hace referencia a su clase en su código. En su ejemplo, esto se ejecutará en la primera línea de su método principal.
Puede validar esto creando un bloque de inicializador estático. Ponga un punto de quiebre en este bloque de inicializador y verá, cuando se lo llame. O incluso más simple ... pon un punto de interrupción en el constructor de SomeObject.
La inicialización de variables estáticas se trata en la Sección 2.11 Inicializadores estáticos de las especificaciones JVM de soles. La especificación no define la implementación de la recolección de basura, así que imagino que las reglas de recolección de basura para objetos estáticos variarán dependiendo de su máquina virtual.
Normalmente no existe la memoria "estática". La mayoría de los vm tienen la generación permanente del montón (donde las clases se cargan), que normalmente no es basura.
Los objetos estáticos se asignan como cualquier otro objeto. Pero, si viven por mucho tiempo, se moverán entre las diferentes generaciones en el recolector de basura. Pero no terminarán en permgenspace.
Si su clase se aferra a este objeto de forma permanente, solo se liberará cuando salga el vm.
Si el campo estático se cambia para hacer referencia a un objeto diferente, el objeto original al que apunta el campo estático es elegible para GC al igual que cualquier otro objeto.
También se puede liberar (incluso si no se anula) si la clase en sí está descargada y el gráfico de objetos completo se corta del montón. Por supuesto, cuando una clase puede ser descargada es un buen tema para una serie de otras preguntas ... :)
Las importaciones no se correlacionan con ninguna instrucción en el código compilado. Establecen alias para usar solo en tiempo de compilación.
Existen algunos métodos reflexivos que permiten que la clase se cargue pero aún no se haya inicializado, pero en la mayoría de los casos, puede suponer que cada vez que se haga referencia a una clase, se habrá inicializado.
Los inicializadores de miembro estático y los bloques estáticos se ejecutan como si fueran todos un bloque de inicializador estático en orden de código fuente.
Un objeto al que se hace referencia a través de una variable miembro estática se referencia fuertemente hasta que la clase se descargue. Un ClassLoader
normal nunca descarga una clase, pero los utilizados por los servidores de aplicaciones lo hacen en las condiciones adecuadas. Sin embargo, es un área difícil y ha sido fuente de muchas fugas de memoria difíciles de diagnosticar, una razón más para no usar variables globales.
Como una bonificación (tangencial), aquí hay una pregunta difícil de considerar:
public class Foo {
private static Foo instance = new Foo();
private static final int DELTA = 6;
private static int BASE = 7;
private int x;
private Foo() {
x = BASE + DELTA;
}
public static void main(String... argv) {
System.out.println(Foo.instance.x);
}
}
¿Qué imprimirá este código? Pruébalo y verás que imprime "6". Hay algunas cosas en juego aquí, y una es el orden de la inicialización estática. El código se ejecuta como si estuviera escrito así:
public class Foo {
private static Foo instance;
private static final int DELTA = 6;
private static int BASE;
static {
instance = null;
BASE = 0;
instance = new Foo(); /* BASE is 0 when instance.x is computed. */
BASE = 7;
}
private int x;
private Foo() {
x = BASE + 6; /* "6" is inlined, because it''s a constant. */
}
}
Cabe señalar que solo el puntero (o cualquier otro tipo primitivo) se almacena en PermGenSpace (ese es el nombre propio del área donde se almacenan las cosas estáticas).
Por lo tanto, el objeto al que hace referencia el puntero se encuentra en el montón normal, como cualquier otro objeto.