tutorial - Gestión de memoria de pila y pila de Java
pilas en java codigo (3)
Quiero saber cómo se asigna la memoria en el siguiente programa:
public class MemoryClass {
public static void main(final String[] args) {
int i = 0;
MemoryClass memoryClass = new MemoryClass();
memoryClass.myMethod(memoryClass);
}
private void myMethod(final Object obj) {
int i = 1;
String s = "HelloWorld!";
}
}
Ahora, según mi entendimiento, el siguiente diagrama describe cómo se lleva a cabo la asignación de memoria:
En el diagrama anterior, memoria , obj y s , que están en la memoria de pila, son en realidad las referencias a sus " objetos reales " que se colocan dentro de la memoria del montón.
Aquí está el conjunto de preguntas que vienen a mi mente:
- ¿Dónde se almacenan los métodos de s ?
- Si hubiera creado otro objeto de
MemoryClass
dentro demyMethod
, ¿JVM asignaría memoria para los mismos métodos nuevamente dentro de la memoria de la pila? - Si JVM liberara la memoria asignada a
myMethod
tan pronto como se complete su ejecución, de ser así, ¿cómo manejaría la situación mencionada en la pregunta 2 ( solo aplicable si JVM asigna memoria varias veces al mismo método )? - ¿Cuál hubiera sido el caso, si solo hubiera declarado s y no lo hubiera inicializado, JVM aún asignaría memoria a todos los métodos de la clase
java.lang.String
, de ser así, por qué?
¿Dónde se almacenan los métodos de s?
Se almacenan en el objeto de clase String; es un objeto cargado por un objeto ClassLoader cuando se hace referencia a String por primera vez en el programa. Todas las implementaciones de la JVM que existían cuando leí sobre esto último nunca desasignaron la memoria para un objeto de clase una vez que se cargó. Está en el montón.
Si hubiera creado otro objeto de MemoryClass dentro de myMethod, ¿JVM asignaría memoria para los mismos métodos nuevamente dentro de la memoria de la pila?
No, los métodos y los datos para los objetos se mantienen por separado, específicamente porque la JVM nunca necesita más de una copia de los métodos.
Si JVM liberara la memoria asignada a myMethod tan pronto como se complete su ejecución, de ser así, ¿cómo manejaría la situación mencionada en la pregunta 2 (solo aplicable si JVM asigna memoria varias veces al mismo método)?
No. Java generalmente no "libera inmediatamente la memoria" de las cosas almacenadas en el montón. Haría que las cosas funcionen muy despacio. Solo libera memoria cuando se ejecuta el recolector de basura, y lo hace solo cuando su algoritmo para ejecutar el recolector de basura decide que es el momento.
¿Cuál hubiera sido el caso, si solo hubiera declarado s y no lo hubiera inicializado, JVM aún asignaría memoria a todos los métodos de la clase java.lang.String, de ser así, por qué?
Esto depende de la implementación de JVM, creo, y tal vez del compilador. Si declara una variable y nunca la usa, es muy posible (y común) que el compilador se dé cuenta de que no tiene ningún uso y no la incluya en el archivo de clase. Si no está en el archivo de clase, nunca se hace referencia, y por lo tanto no se carga y sus métodos, etc. Si el compilador lo coloca de todas formas pero nunca se hace referencia, el ClassLoader no tendría ningún motivo para cargarlo, pero soy un poco vago sobre si se cargaría o no. Podría depender de la implementación de JVM; ¿carga cosas porque hay variables de la clase o solo cuando están referenciadas? ¿Cuántos algoritmos de ClassLoader pueden bailar en la cabeza de un PIN de 4 dígitos?
Lo invito a leer sobre JVM y ClassLoaders y demás; ganará mucho más leyendo una explicación de cómo funciona en lugar de tocarla con ejemplos que pueda imaginar.
Ya que la respuesta aceptada del arsy y la respuesta de hagrawal son claras, solo quiero dar más detalles sobre la cuarta pregunta:
¿Cuál hubiera sido el caso, si solo hubiera declarado s y no lo hubiera inicializado, JVM aún asignaría memoria a todos los métodos de la clase java.lang.String, de ser así, por qué?
Básicamente, si bien es cierto que los datos de clase, que tienen la información de campos y métodos, se almacenan en la generación permanente (meta-espacio desde JDK-8 en adelante), es importante tener en cuenta que son los objetos dentro de java.lang. Clase de cadena (como el char [] que contiene toda la información de caracteres para esa cadena) para la cual los datos se asignan en el montón.
Esto no sucede hasta que se crea un nuevo objeto de cadena, ya sea utilizando la palabra clave ''nueva'' o creando una nueva cadena literal (por ejemplo, "helloworld").
Lo primero es lo primero : asumo que sus preguntas saldrán después de leer this artículo ( porque allí veo un diagrama muy similar al suyo ), por lo que no citaré ni resaltaré ninguno de los puntos que se mencionan allí y trataré de responder. a tus preguntas con puntos que no eran tan obvios en ese post.
Al leer todas sus preguntas, mi impresión es que tiene claro cómo se asigna la memoria en la pila y el montón, pero tiene dudas sobre los metadatos de las clases, es decir, en qué lugar de la memoria se almacenarán los métodos de las clases y cómo se reciclarán. Entonces, primero déjame tratar de explicar las áreas de memoria de JVM:
Áreas de Memoria JVM
Permítanme comenzar poniendo estos 2 diagramas que representan las áreas de memoria de JVM:
Ahora, lo que queda claro en los diagramas anteriores es la estructura de árbol de la memoria JVM y trataré de iluminar la misma ( @Adit: tenga en cuenta que el área que le concierne es el espacio PermGen o el espacio de generación permanente de la memoria que no es de pila ) .
- Memoria de pila
- Generación joven
- Espacio edén
- Espacio Sobreviviente
- Antigua generacion
- Generación de tenencia
- Generación joven
- Memoria no heap
- Generación permanente
- Caché de código ( creo que incluía "solo" por HotSpot Java VM )
Memoria de pila
La memoria de almacenamiento dinámico es el área de datos de tiempo de ejecución desde la cual la VM Java asigna memoria para todas las instancias y matrices de clase. El montón puede ser de un tamaño fijo o variable. El recolector de basura es un sistema automático de administración de memoria que reclama memoria de pila para objetos.
Generación joven
La generación joven es el lugar donde se crean todos los nuevos objetos. Cuando se llena la generación joven, se realiza la recolección de basura. Esta recolección de basura se llama Minor GC. Generación joven se divide en 2 partes por debajo
Espacio Edén: el grupo desde el cual la memoria se asigna inicialmente para la mayoría de los objetos.
Espacio de sobreviviente: el grupo que contiene objetos que han sobrevivido a la recolección de basura del espacio de Eden.
Antigua generacion
La memoria de la vieja generación contiene los objetos que son de larga vida y que han sobrevivido después de muchas rondas de Minor GC. Por lo general, la recolección de basura se realiza en la memoria de la vieja generación cuando está llena. La recolección de basura de la antigua generación se denomina GC mayor y generalmente toma más tiempo. La vieja generación contiene la siguiente parte:
Espacio permanente: el grupo que contiene objetos que han existido durante algún tiempo en el espacio de sobrevivientes.
Memoria no de montón
La memoria que no es de pila incluye un área de método compartida entre todos los subprocesos y la memoria requerida para el procesamiento interno u optimización para la máquina virtual Java. Almacena estructuras por clase, como una agrupación constante de tiempo de ejecución, datos de campo y método, y el código para métodos y constructores. El área del método es parte lógica del montón pero, dependiendo de la implementación, una máquina virtual Java no puede recolectar basura ni compactarla. Al igual que la memoria de almacenamiento dinámico, el área del método puede ser de un tamaño fijo o variable. La memoria para el área de método no necesita ser contigua.
Generación permanente
La agrupación que contiene todos los datos reflexivos de la propia máquina virtual, como los objetos de clase y método. Con las máquinas virtuales de Java que utilizan el intercambio de datos de clase, esta generación se divide en áreas de solo lectura y de lectura y escritura.
Código de caché
El HotSpot Java VM también incluye un caché de código, que contiene la memoria que se utiliza para la compilación y el almacenamiento del código nativo.
Respondiendo específicamente a las preguntas de OP
¿Dónde se almacenan los métodos de s?
Memoria no de pila -> Generación permanente
Si hubiera creado otro objeto de MemoryClass dentro de myMethod, ¿JVM asignaría memoria para los mismos métodos nuevamente dentro de la memoria de la pila?
La memoria de la pila solo contiene variables locales, por lo que su ORV (variable de referencia del objeto) de la nueva MemoryClass
de MemoryClass
aún se creará en el marco de la pila de myMethod
, pero JVM no cargará todos los métodos, metadatos, etc. de la MemoryClass
de MemoryClass
nuevamente en "Generación permanente".
JVM carga la clase solo una vez y cuando carga la clase, entonces el espacio se asigna en la "Generación Permanente" para esa clase y eso sucede solo una vez mientras la JVM carga la clase.
Si JVM liberara la memoria asignada a myMethod tan pronto como se complete su ejecución, de ser así, ¿cómo manejaría la situación mencionada en la pregunta 2 (solo aplicable si JVM asigna memoria varias veces al mismo método)?
El marco de la pila creado para myMethod
se eliminará de la memoria de la pila, por lo que toda la memoria creada para las variables locales se limpiará, pero esto no significa que JVM limpiará la memoria asignada en la "Generación Permanente" para la clase de los objetos que ha creado. en mi myMethod
¿Cuál hubiera sido el caso, si solo hubiera declarado s y no lo hubiera inicializado, JVM aún asignaría memoria a todos los métodos de la clase java.lang.String, de ser así, por qué?
Específicamente hablando de String
clase String
, JVM habría asignado el espacio para String
en "Generación Permanente" demasiado pronto, mientras se inicia JVM y si inicia su variable String o no, no importa desde la perspectiva de "Generación Permanente".
Hablando de otras clases definidas por el usuario, JVM cargaría la clase y asignaría memoria en "Generación Permanente" tan pronto como defina la clase, de nuevo, incluso si no crea un objeto de la clase, la memoria se asigna en "Generación Permanente" (área que no es de pila ) y cuando creas un objeto de la clase, la memoria se asigna en "Eden Space" ( área de pila ).
Fuentes de información anterior y lecturas adicionales:
- http://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.html
- http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java
- https://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
- ¿La terminología del montón de Java: generaciones jóvenes, viejas y permanentes?