Hace algún tiempo escribí un par de publicaciones sobre la recolección de basura en Java y Java se pasa por valor . Después de eso, recibí muchos correos electrónicos para explicar sobre el espacio de pila de Java , la memoria de pila de Java , la asignación de memoria en Java y cuáles son las diferencias entre ellos. Verá muchas referencias a la memoria de pila y pila en Java, libros y tutoriales de Java EE, pero no hay una explicación completa de qué es la memoria de pila y pila en términos de un programa.
Espacio de montón de Java
El espacio del montón de Java es utilizado por el entorno de ejecución de Java para asignar memoria a objetos y clases JRE. Siempre que creamos un objeto, se crea en el espacio del montón. La recolección de elementos no utilizados se ejecuta en la memoria del montón para liberar la memoria utilizada por objetos que no tienen ninguna referencia. Cualquier objeto creado en el espacio del montón tiene acceso global y se puede hacer referencia a él desde cualquier parte de la aplicación.
Memoria de pila Java
La memoria de pila de Java se utiliza para la ejecución de un subproceso. Contiene valores específicos de métodos que son de corta duración y referencias a otros objetos en el montón a los que se hace referencia desde el método. La memoria de pila siempre se referencia en orden LIFO (último en entrar, primero en salir). Siempre que se invoca un método, se crea un nuevo bloque en la memoria de pila para que el método contenga valores primitivos locales y referencias a otros objetos en el método. Tan pronto como el método termina, el bloque deja de usarse y queda disponible para el siguiente método. El tamaño de la memoria de pila es muy inferior en comparación con la memoria de montón.
Memoria de pila y montón en programas Java
Comprendamos el uso de la memoria Heap y Stack con un programa simple.
package com.journaldev.test;public class Memory {public static void main(String[] args) { // Line 1int i=1; // Line 2Object obj = new Object(); // Line 3Memory mem = new Memory(); // Line 4mem.foo(obj); // Line 5} // Line 9private void foo(Object param) { // Line 6String str = param.toString(); //// Line 7System.out.println(str);} // Line 8}
La siguiente imagen muestra la memoria de pila y montón con referencia al programa anterior y cómo se utilizan para almacenar primitivas, objetos y variables de referencia. Repasemos los pasos de la ejecución del programa.
- Tan pronto como ejecutamos el programa, carga todas las clases de Runtime en el espacio de Heap. Cuando se encuentra el método main() en la línea 1, Java Runtime crea memoria de pila para que la use el subproceso del método main().
- Estamos creando una variable local primitiva en la línea 2, por lo que se crea y se almacena en la memoria de la pila del método main().
- Dado que estamos creando un objeto en la tercera línea, se crea en la memoria del montón y la memoria de la pila contiene la referencia para él. Un proceso similar ocurre cuando creamos un objeto de memoria en la cuarta línea.
- Ahora, cuando llamamos al método foo() en la quinta línea, se crea un bloque en la parte superior de la pila para que lo use el método foo(). Como Java es un método de paso por valor, se crea una nueva referencia a Object en el bloque de pila foo() en la sexta línea.
- Se crea una cadena en la séptima línea, va al grupo de cadenas en el espacio del montón y se crea una referencia en el espacio de pila foo() para ella.
- El método foo() finaliza en la octava línea, en este momento el bloque de memoria asignado para foo() en la pila queda libre.
- En la línea 9, el método main() finaliza y se destruye la memoria de pila creada para el método main(). Además, el programa finaliza en esta línea, por lo que Java Runtime libera toda la memoria y finaliza la ejecución del programa.
Diferencia entre el espacio de pila y la memoria de pila de Java
Con base en las explicaciones anteriores, podemos concluir fácilmente las siguientes diferencias entre la memoria Heap y la memoria Stack.
- La memoria del montón es utilizada por todas las partes de la aplicación, mientras que la memoria de pila es utilizada solo por un hilo de ejecución.
- Siempre que se crea un objeto, este se almacena en el espacio del montón y la memoria de pila contiene la referencia a él. La memoria de pila solo contiene variables primitivas locales y variables de referencia a objetos en el espacio del montón.
- Los objetos almacenados en el montón son accesibles globalmente, mientras que otros subprocesos no pueden acceder a la memoria de la pila.
- La gestión de memoria en la pila se realiza de manera LIFO, mientras que en la memoria Heap es más compleja porque se utiliza de manera global. La memoria Heap se divide en generación joven, generación antigua, etc. Más detalles en Recolección de basura de Java .
- La memoria de pila tiene una vida útil corta, mientras que la memoria de montón vive desde el principio hasta el final de la ejecución de la aplicación.
- Podemos utilizar las opciones -Xms y -Xmx de JVM para definir el tamaño de inicio y el tamaño máximo de la memoria del montón. Podemos utilizar -Xss para definir el tamaño de la memoria de la pila.
- Cuando la memoria de la pila está llena, el entorno de ejecución de Java lanza un error,
java.lang.StackOverFlowErrormientras que si la memoria del montón está llena, lanzajava.lang.OutOfMemoryError: Java Heap Spaceun error. - El tamaño de la memoria de pila es muy inferior en comparación con la memoria de montón. Debido a la simplicidad en la asignación de memoria (LIFO), la memoria de pila es muy rápida en comparación con la memoria de montón.
Eso es todo sobre Java Heap Space vs Stack Memory en términos de aplicación Java, espero que aclare sus dudas con respecto a la asignación de memoria cuando se ejecuta cualquier programa Java.
Referencia: https://en.wikipedia.org/wiki/Java_memory_model .