Stack Heap

Stack & Heap

En Java, Stack y Heap son dos áreas de la memoria utilizadas para almacenar datos durante la ejecución de un programa. Estas dos áreas se gestionan de manera diferente y tienen propósitos distintos, lo que es clave para comprender cómo se maneja la memoria en un programa Java y optimizar su uso.

A continuación, veremos en detalle qué son Stack y Heap, sus diferencias, y cómo funcionan en Java.


1. Stack

El Stack es una estructura de datos de memoria utilizada para almacenar datos locales y el estado de ejecución de un programa, como las variables locales y las llamadas a funciones o métodos.

Características del Stack:

  • Memoria organizada de forma LIFO (Last In, First Out - Último en entrar, primero en salir): El último dato agregado al stack es el primero en ser retirado.
  • Almacenamiento de variables locales: Las variables locales, como los parámetros de los métodos y las variables dentro de un método, se almacenan en el stack.
  • Crecimiento y decrecimiento controlados: Cuando un método es llamado, se crea un nuevo marco de pila (stack frame) que contiene sus variables locales. Cuando el método termina, ese marco es destruido.
  • Acceso rápido: El stack es muy rápido debido a la naturaleza LIFO y su sencilla organización.
  • Memoria limitada: La cantidad de memoria disponible para el stack es limitada, lo que significa que el uso excesivo de la pila (por ejemplo, demasiadas llamadas recursivas) puede provocar un desbordamiento de pila (StackOverflowError).
  • Almacenamiento temporal: Los datos almacenados en el stack solo existen durante la ejecución de un método. Una vez que el método finaliza, las variables locales se eliminan automáticamente.

Ejemplo de uso del Stack:

public class StackExample {
    public static void main(String[] args) {
        int a = 5;  // Variable local en el stack
        int b = 10; // Otra variable local en el stack
        int result = suma(a, b);  // Llamada a un método, se crea un nuevo stack frame
        System.out.println("El resultado es: " + result);
    }

    public static int suma(int x, int y) {  // Las variables 'x' y 'y' se almacenan en el stack
        return x + y;
    }
}

En este ejemplo:

  • Las variables a y b se almacenan en el stack dentro del método main.
  • Al llamar al método suma, se crea un nuevo stack frame para las variables x y y, y cuando el método finaliza, esas variables son eliminadas automáticamente.

¿Cuándo se utiliza Stack?

  • Variables locales: Almacena las variables locales, como los parámetros de los métodos.
  • Llamadas a métodos: Gestiona el estado de las llamadas a funciones y métodos.
  • Recursión: Al almacenar el estado de cada llamada recursiva, el stack se puede utilizar para realizar llamadas recursivas, aunque con un límite en la profundidad.

2. Heap

El Heap es un área de la memoria utilizada para almacenar objetos dinámicos y datos cuya vida útil no está limitada por la ejecución de un único método. En Java, todos los objetos creados mediante el operador new se almacenan en el heap.

Características del Heap:

  • Memoria dinámica: A diferencia del stack, el heap se utiliza para almacenar objetos cuyo tamaño no se conoce en tiempo de compilación y cuya duración puede ser mayor que la duración de un solo método.
  • Almacenamiento de objetos: Todos los objetos y sus datos asociados (como los arrays) se almacenan en el heap.
  • Acceso más lento: El acceso al heap es más lento que al stack debido a la complejidad en la gestión de la memoria (asignación y liberación de espacio).
  • Recolección de basura (Garbage Collection): En Java, la gestión de la memoria en el heap es automática gracias al recolector de basura. Los objetos que ya no son referenciados se eliminan automáticamente para liberar espacio.
  • Memoria de tamaño mayor: El heap es mucho más grande que el stack y no tiene las limitaciones de tamaño de este último, aunque el tamaño del heap puede ser ajustado a través de parámetros de la JVM.

Ejemplo de uso del Heap:

public class HeapExample {
    public static void main(String[] args) {
        Persona persona1 = new Persona("Juan", 30);  // El objeto 'persona1' se almacena en el heap
        Persona persona2 = new Persona("Ana", 25);   // Otro objeto 'persona2' se almacena en el heap

        persona1.mostrarDetalles();
        persona2.mostrarDetalles();
    }
}

class Persona {
    String nombre;
    int edad;

    public Persona(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }

    public void mostrarDetalles() {
        System.out.println("Nombre: " + nombre + ", Edad: " + edad);
    }
}

En este ejemplo:

  • Los objetos persona1 y persona2 son creados en el heap mediante el operador new.
  • Las referencias a estos objetos son almacenadas en el stack (en las variables locales persona1 y persona2).

¿Cuándo se utiliza Heap?

  • Objetos: Todos los objetos creados mediante new se almacenan en el heap.
  • Arrays: Los arrays también se almacenan en el heap, independientemente de si son primitivos o de objetos.
  • Duración prolongada: Los objetos que necesitan vivir más allá del ámbito de un único método o función, como aquellos que son pasados entre métodos, se almacenan en el heap.

Diferencias clave entre Stack y Heap

Característica Stack Heap
Almacenamiento Almacena variables locales y el estado de métodos. Almacena objetos creados mediante new.
Tamaño Más pequeño, limitado en tamaño. Más grande, depende de la configuración de la JVM.
Estructura de memoria Estructura LIFO (Last In, First Out). Memoria dinámica, asignación de espacio no estructurada.
Acceso Acceso rápido, el último elemento insertado es el primero en salir. Acceso más lento debido a la gestión dinámica de memoria.
Gestión de memoria El espacio es liberado automáticamente cuando el método termina. Requiere recolección de basura (Garbage Collection) para liberar memoria.
Duración Los datos solo existen durante la ejecución del método. Los objetos existen mientras tengan referencias.
Uso típico Variables locales, llamadas a métodos. Objetos, arrays, almacenamiento de datos de duración prolongada.