Gestión de la memoria (Stack y Heap) en C++¶
Cuando ejecutamos un programa, nuestro sistema operativo le asigna un proceso con algo de memoria, llamada la memoria virtual, donde ejecutarse. Esa memoria virtual se divide en segmentos:
- El segmento de texto, conocido como segmento de código, contiene las instrucciones ejecutables y es solo de lectura: https://en.wikipedia.org/wiki/Code_segment.
- El segmento de datos contiene la inicialización de las variables estáticas, globales y estáticas locales: https://en.wikipedia.org/wiki/Data_segment.
- El segmento heap (montón) contiene memoria reservada dinámicamente por el programador para almacenar variables temporales, se gestiona con las instrucciones
malloc
,calloc
,realloc
yfree
. Es un segmento compartido por todos los subprocesos, bibliotecas compartidas y módulos cargados dinámicamente en un proceso: https://en.wikipedia.org/wiki/Manual_memory_management. - El segmento stack (pila), ubicado en la parte superior de la memoria, contiene la pila de llamadas (call stack). Se trata de una estructura LIFO (último en llegar primero en salir) donde se almacenan los argumentos pasados al programa, las cadenas del entorno, argumentos de las funciones, variables locales no inicializadas, además de almacenar el registro de llamada de funciones y el retorno: https://en.wikipedia.org/wiki/Stack-based_memory_allocation.
Diferencias entre stack y heap¶
Los segmentos más interesantes para nosotros son el montón (heap) y la pila (stack), así que voy a resumir sus diferencias clave en una tabla:
Parámetro | Stack (pila) | Heap (montón) |
---|---|---|
Estructura de datos | Estructura de datos lineal. | Estructura de datos jerárquica. |
Velocidad de acceso | Acceso de alta velocidad. | Más lento en comparación con la pila. |
Gestión del espacio | Es un espacio administrado eficientemente por el sistema operativo para que la memoria nunca se fragmente. | El espacio de pila no se usa de manera tan eficiente. La memoria puede fragmentarse como bloques de memoria asignados y liberados. |
Acceso | Solo variables locales. | Permite acceder a variables de forma global. |
Límite de tamaño | El límite depende del sistema operativo. | No tiene un límite específico. |
Redimensión | Las variables no pueden cambiar de tamaño. | Las variables pueden cambiar de tamaño. |
Asignación de memoria | La memoria se asigna en un bloque contiguo. | La memoria se asigna en cualquier orden aleatorio. |
Asignación y desasignación | Se realiza automáticamente mediante instrucciones del compilador. | Lo hace manualmente el programador. |
Desasignación | No requiere desasignar variables. | Se necesita una desasignación explícita. |
Coste | Menor. | Mayor. |
Implementación | Matrices simples, memoria dinámica y basada en listas vinculadas. | Matrices y árboles. |
Mayor problema | Escasez de memoria. | Fragmentación de la memoria. |
Localidad de referencia | Instrucciones automáticas en tiempo de compilación. | Adecuado. |
Flexibilidad | Tamaño fijo. | Redimensionable. |
Tiempo de acceso | Más rápido. | Más lento. |
¿Cuándo utilizar el montón y la pila?¶
-
El montón (heap) debe utilizarse cuando se necesita asignar un gran bloque de memoria. Por ejemplo crear una matriz de gran tamaño o una estructura demasiado grande para mantener una variable durante mucho tiempo.
-
La pila (stack) es mejor utilizarla cuando se trabaja con variables relativamente pequeñas que solo se requieren mientras una función está viva, debido a que provee un acceso más fácil y rápido.
Última edición: 08 de Mayo de 2022