Heap Space y Stack Memory en Java
En este artículo vamos a ver el Heap Space y Stack Memory en Java y como se hace uso de estas dos memorias para optimizar los recursos en la JVM.
¿Qué es la JVM?
La JVM o la Java Virtual Machine es una máquina virtual que ejecutar programas Java o programas escritos en lenguajes que compilen el byte code (código de bytes) de Java.
Memory Stack en la JVM
La memoria Stack se usa para almacenar las variables locales (cuyo ámbito de acción está limitada solo a la función donde se declaró) y también las llamadas de funciones en Java.
La memory Stack es usada para la ejecución de un thread teniendo referencia a otros objetos del heap.
A la memoria Stack siempre se le hace referencia en modo LIFO (Last in first out). Cuando invocamos un método desde una aplicación, se crea un nuevo bloque en la memoria de Stack para almacenar valores y referencias a otros objetos en el método.
Cuando un método que se ejecuta finaliza su ejecución su espacio correspondiente en la pila finaliza, el flujo vuelve al método de llamada y queda espacio disponible para volver a ser utilizado por el siguiente método.
Cómo funciona el Heap Space en la JVM
El espacio Heap es usado para la colocación dinámica de objetos Java y clases JRE en tiempo de ejecución. Los nuevos objetos que se van necesitando, son creados siempre en el espacio HEAP y la referencia a estos objetos son almacenados en la memory stack.
Todos los objetos que creemos tienen acceso global y podemos acceder a ellos desde cualquier parte de nuestra aplicación.
En función de como se almacenan estos objetos dentro del Heap podríamos realizar las siguientes clasificaciones.
- Young generation: Es donde se guardan los objetos nuevos, se hace un uso menor del garbage collector.
- Survivor space: En este área se encuentran los objetos que han sobrevivido del Garbage Collector del Young Generation. Está área se encuentra dividida en los espacios S0 y S1.
- Old generation: En este área se almacenan los objetos que han sobrevivido durante un largo período de tiempo. Estos objetos han pasado del área de Young Generation a este área.
- Permanent generation: Metadata de la JVM para ejecutar métodos y ejecutar la aplicación.
- Code Cache: Code Cache es un área en donde se almacena el bytecode compilado a código nativo.
Cuando el espacio Heap esta lleno, Java nos devuelve el típico error Java.lang.OutOfMemoryError. Cuando necesitamos limpiar el Heap o vaciarla es cuando se llama al Garbage Collector, ya que el Heap de diferencia del Stack no se vacía de manera automática.
Diagrama de funcionamiento Heap and Stack en Java
Vamos a ver mediante un ejemplo el funcionamiento del espacio Heap y la memoria Stack en java.
public class User() { private Long id; private String name; public User(int id, String name) { this.id = id; this.name = name; } //Getter & setters } public class LoadUser() { public static void createUser() { int id = 1; //stack memory almacena el valor de id String name = "NOEL"; User user = null; //se almacena en stack y un puntero al objeto actual en el heap user = buildUser(id, name); } private static User buildUser(int id, String name) { return new User(id, name); } }
Vamos a ver los pasos del diagrama anterior:
- Creamos un espacio en el stack memory para almacenar los valores primitivos y referencias del método createUser().
- El stack memory almacena el valor del id, es decir, 1.
- La variable user se crea en el stack y apunta al objeto real en el Heap Space.
- La llamada al constructor de user asigna más memoria en el Stack Memory, y almacena la referencia del objeto en el Stack Memory, el valor del Id y la referencia al nombre que apunta a la cadena creada en el Heap Space.
- Con la llamada a buildUser se realiza una asignación adicional en el Stack Memory.
- En el Heap Space se guardan todas las variables de la instancia del objeto user que se acaba de crear.
Difference Between Stack and Heap Memory
Stack Memory | Heap Space | |
---|---|---|
Ordenamiento de elementos | Los elementos se ordenan en modo LIFO | Ordenamiento dinámico. |
Tamaño de la memoria | En más pequeño en tamaño | Es mayor en tamaño |
Excepciones | Se lanzará un StackOverFlowError si el tamaño del stack es mayor que el límite. Se evita incrementando el stack. | La JVM lanza un java.lang.OutOfMemoryError en los casos en los que la JVM es incapaz de crear un nuevo método nativo. |
Implementación | Su implementación es compleja | Su implementación es más fácil |
Orden de asignación | La asignación de la memoria es continua | La asignación es random. |
Thread-Safety | Cada thread tiene su propio stack por lo que es thread-safe. | No es thread-safe así una buena sincronización del código es necesaria. |
Cost | Es menos costoso | Es más costoso |
Flexibilidad | No es nada flexible ya que no podemos modificar las asignaciones de la memoria. | Es flexibe porque podemos modificar la asignación en la memoria. |
Aplicación | Guarda objetos y elementos que tienen un corto período de vida como métodos y variables y referencias a las variables. | Almacena objetos y clases de la JRE. |
Java Options | La memory Stack puede ser incrementada haciendo uso de JVM option -Xss. | Podemos aumentar o disminuir la memoria heap haciendo uso de –Xmx y -Xms en las JVM options. |
Asignación / Desasignación | Tanto asignar como desasignar es realizado de manera automática por el compilador. | Lo realiza el programa. |
Distribution | Una pila o stack separada es creada por cada objeto. | La pila o stack se comparte entre todos los threads creados. |
Eficiencia | El acceso, la asignación y la desasignar es más rápido. | Acesso, asignación y desasignar es más lento. |
Conclusión
En esta entrada hemos sobre el Heap Space y Stack Memory en Java, hemos visto las principales diferencias entre las dos memorias. Así como su uso dentro de la JVM.
Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com o también nos puedes contactar por nuestras redes sociales Facebook o twitter y te ayudaremos encantados!