Utilizar la asignación de memoria de pila frente a montón en C++

Jinku Hu 12 octubre 2023
Utilizar la asignación de memoria de pila frente a montón en C++

Este artículo explicará varios métodos de cómo utilizar la asignación de memoria pila frente a pila en C++.

Diferencia entre la pila y la memoria del montón en C++

Cuando queremos discutir los conceptos de memoria, es mejor pensar en términos de sistemas donde se ejecutan los programas de usuario más comunes. La mayoría de los programas de usuario se ejecutan en un entorno de sistema operativo, que administra los recursos de hardware por nosotros y se encarga de diversas tareas que serían demasiado complejas o ineficientes para que las manejara un programa de usuario. Una de esas tareas es administrar la memoria del hardware directamente. Por tanto, casi todos los sistemas operativos proporcionan estructuras y funciones especiales para interactuar con la memoria del hardware. Dos conceptos comunes en las estructuras de memoria proporcionadas por el sistema operativo son pila y montón.

Una pila es una región de memoria reservada para cada programa en ejecución en el sistema y funciona de manera LIFO. Es decir, cuando el programa comienza a ejecutar la función main, esta última obtiene su marco de pila (un subconjunto de la memoria de pila), donde las variables locales y las direcciones de retorno de llamadas de función se almacenan automáticamente. Una vez que el main llama a otra función, se crea un nuevo stack frame después del anterior de manera continua. El marco de pila más nuevo almacenará los objetos locales para la función correspondiente y cuando regrese, esta memoria se desocupará.

Tenga en cuenta que el tamaño de la pila está fijo en la mayoría de los sistemas de forma predeterminada, pero se puede personalizar hasta cierto punto si el usuario tiene necesidades especiales. La limitación de tamaño de la memoria de pila la hace adecuada para objetos pequeños y en su mayoría temporales. Por ejemplo, el tamaño de pila predeterminado para el programa de usuario en el sistema operativo Linux es de 8 MB. Puede ser más pequeño que una sola foto JPEG que un programa pueda necesitar procesar, por lo que el usuario debe usar este espacio con mucha precaución. Las variables declaradas en el siguiente fragmento de código se almacenan en la memoria de pila. Como regla general, cada variable local se asigna en la pila si no tiene especificadores especiales como static o volatile.

#include <iostream>

using std::cout;
using std::endl;

int main() {
  int var1;
  int var2 = 123;
  int arr1[4] = {1, 2, 3, 4};
  int var3 = var2;

  cout << var1 << endl;
  cout << var2 << endl;
  cout << var3 << endl;

  return EXIT_SUCCESS;
}

Producción :

0
123
123

Por otro lado, hay una región de memoria llamada - heap (también conocida como free store), donde los objetos grandes pueden ser almacenados y asignaciones hechas manualmente por el programador durante el tiempo de ejecución. Estas dos características hacen que la memoria del montón sea de naturaleza dinámica, ya que no es necesario determinar su tamaño en tiempo de compilación ni en ningún momento durante la ejecución del programa. El programa puede llamar a funciones especiales y solicitar las asignaciones del sistema operativo. Tenga en cuenta que la memoria del montón puede parecer infinita desde la perspectiva del programa, ya que no se limita a llamar a otra función de asignación para solicitar más memoria. Aunque, el sistema operativo administra la memoria para todos los procesos en ejecución; y podría rechazar nuevas asignaciones cuando no haya más memoria física disponible.

El sistema de memoria en el sistema operativo es bastante complejo y requiere una comprensión de varios conceptos específicos de SO / hardware, por lo que solo cubrimos más que lo mínimo sobre las memorias de pila y pila en este tema. La gestión manual de la memoria del montón en lenguaje C++ se puede realizar utilizando los operadores new/delete o las funciones malloc/free. Tenga en cuenta que estas funciones funcionan de manera similar, donde el usuario generalmente especifica la cantidad de bytes a asignar y devuelve la dirección donde se asignó la misma cantidad de memoria. En consecuencia, el programador puede operar en la región de memoria dada según sea necesario.

El siguiente ejemplo de código muestra varios casos de asignación de diferentes objetos en la memoria del montón. Una característica importante de la administración de memoria manual es devolver la región de memoria asignada al sistema operativo cuando ya no se necesita. Esta última operación se realiza mediante llamadas delete/free correspondientes a sus contrapartes de asignación. Si el programa no libera la memoria innecesaria, existe el riesgo de que el sistema operativo se quede sin memoria y, como resultado, el programa se elimine. Sin embargo, tenga en cuenta que se espera que el problema anterior ocurra principalmente en programas de larga ejecución y se caracterizan como errores de pérdida de memoria.

#include <iostream>

using std::cout;
using std::endl;

int main() {
  auto var4 = new int;
  cout << var4 << endl;

  int *arr2 = new int[4];
  auto arr3 = new int[4];
  cout << arr2 << endl;
  cout << arr3 << endl;

  delete var4;
  delete[] arr2;
  delete[] arr3;
  return EXIT_SUCCESS;
}
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artículo relacionado - C++ Memory