stringtranslate.com

Asignación de memoria basada en pila

Una pila típica que almacena datos locales e información de llamadas para llamadas a procedimientos anidados (no necesariamente procedimientos anidados ). Esta pila crece hacia abajo desde su origen. El puntero de la pila apunta al dato superior actual de la pila. Una operación de inserción disminuye el puntero y copia los datos a la pila; una operación emergente copia datos de la pila y luego incrementa el puntero. Cada procedimiento llamado en el programa almacena información de retorno del procedimiento (en amarillo) y datos locales (en otros colores) empujándolos a la pila.

Las pilas en las arquitecturas informáticas son regiones de la memoria donde los datos se agregan o eliminan según el último en entrar, primero en salir (LIFO) .

En la mayoría de los sistemas informáticos modernos, cada subproceso tiene una región de memoria reservada denominada pila. Cuando se ejecuta una función, puede agregar algunos de sus datos de estado local a la parte superior de la pila; cuando la función sale, es responsable de eliminar esos datos de la pila. Como mínimo, la pila de un hilo se utiliza para almacenar la ubicación de una dirección de retorno proporcionada por la persona que llama para permitir que las declaraciones de devolución regresen a la ubicación correcta.

La pila se utiliza a menudo para almacenar variables de longitud fija locales para las funciones actualmente activas. Los programadores pueden optar además por utilizar explícitamente la pila para almacenar datos locales de longitud variable. Si una región de memoria se encuentra en la pila del subproceso, se dice que esa memoria ha sido asignada en la pila, es decir, asignación de memoria basada en pila (SBMA). Esto contrasta con una asignación de memoria basada en montón (HBMA). El SBMA suele estar estrechamente relacionado con una pila de llamadas a funciones .

Ventajas y desventajas

Debido a que los datos se agregan y eliminan según el principio de último en entrar, primero en salir, la asignación de memoria basada en pila es muy simple y generalmente mucho más rápida que la asignación de memoria basada en montón (también conocida como asignación de memoria dinámica ), por ejemplo , C.malloc

Otra característica es que la memoria en la pila se recupera automática y muy eficientemente cuando la función sale, lo que puede ser conveniente para el programador si los datos ya no son necesarios. [1] (Lo mismo se aplica a longjmp si se movió a un punto antes de que allocaocurriera la llamada). Sin embargo, si los datos deben conservarse de alguna forma, deben copiarse de la pila al montón antes de la función. salidas. Por lo tanto, la asignación basada en pila es adecuada para datos temporales o datos que ya no son necesarios después de que sale la función actual.

El tamaño de pila asignado a un subproceso puede ser tan pequeño como unos pocos bytes en algunas CPU pequeñas. Asignar más memoria en la pila de la que está disponible puede provocar un bloqueo debido al desbordamiento de la pila . allocaEsta es también la razón por la que generalmente se evita que las funciones que se utilizan se incluyan en línea: [2] si dicha función se incluyera en un bucle, la persona que llama sufriría un crecimiento inesperado en el uso de la pila, lo que haría mucho más probable un desbordamiento.

La asignación basada en pila también puede causar problemas menores de rendimiento: conduce a marcos de pila de tamaño variable, por lo que es necesario gestionar tanto los punteros de pila como los de marco (con marcos de pila de tamaño fijo, el puntero de pila es redundante debido a la multiplicación del marco de pila puntero por el tamaño de cada cuadro). Esto suele ser mucho menos costoso que llamar mallocy freede todos modos. En particular, si la función actual contiene llamadas a alloca y bloques que contienen datos locales de longitud variable, entonces se produce un conflicto entre los intentos de alloca de aumentar el marco de pila actual hasta que la función actual salga versus la necesidad del compilador de colocar variables locales de longitud variable en la misma ubicación en el marco de la pila. Este conflicto normalmente se resuelve creando una cadena separada de almacenamiento en montón para cada llamada a alloca. [3] La cadena registra la profundidad de la pila en la que se produce cada asignación; las llamadas posteriores a alloca en cualquier función recortan esta cadena hasta la profundidad de la pila actual para eventualmente (pero no inmediatamente) liberar cualquier almacenamiento en esta cadena. También se puede utilizar una llamada a alloca con un argumento de cero para activar la liberación de memoria sin asignar más memoria. Como consecuencia de este conflicto entre alloca y el almacenamiento de variables locales, usar alloca podría no ser más eficiente que usar malloc.

Interfaz del sistema

Muchos sistemas tipo Unix , así como Microsoft Windows, implementan una función llamada allocapara asignar dinámicamente memoria de pila de una manera similar a la basada en montón malloc. Un compilador normalmente lo traduce en instrucciones en línea que manipulan el puntero de la pila, de manera similar a cómo se manejan las matrices de longitud variable . [4] Aunque no es necesario liberar explícitamente la memoria, existe el riesgo de que se produzca un comportamiento indefinido debido al desbordamiento de la pila. [5] La función estaba presente en sistemas Unix ya en 32/V (1978), pero no forma parte del Estándar C ni de ningún estándar POSIX .

En Microsoft Windows existe una versión más segura de allocacall _malloca, que asigna en el montón si el tamaño de la asignación es demasiado grande e informa errores de desbordamiento de la pila. Requiere el uso de _freea. [6] gnulib proporciona una interfaz equivalente, aunque en lugar de generar una excepción SEH en caso de desbordamiento, delega malloccuando se detecta un tamaño demasiado grande. [7] Se puede emular una característica similar usando contabilidad manual y verificación de tamaño, como en los usos de alloca_accountglibc. [8]

Algunas familias de procesadores, como el x86 , tienen instrucciones especiales para manipular la pila del subproceso que se está ejecutando actualmente. Otras familias de procesadores, incluidas RISC-V , PowerPC y MIPS , no tienen soporte explícito de pila, sino que se basan en convenciones y delegan la gestión de pila a la interfaz binaria de aplicaciones (ABI) del sistema operativo.

VLA automáticos

Además, desde la versión C C99 (opcional desde C11), es posible crear una matriz en la pila dentro de una función, de forma automática, conocida como auto VLA ( matriz de longitud variable ). [9]

void f ( int longitudarray ) { int b [ longitudarray ]; // auto VLA: la longitud de esta matriz se establece en // el momento de la invocación de la función/generación de la pila. for ( int i = 0 ; i < arrayLength ; i ++ ) b [ i ] = 1 ; // al final de esta función, b[] está dentro del marco de la pila y // desaparecerá cuando la función salga, por lo que no se requiere una llamada explícita a free(). }                    

Ver también

Referencias

  1. ^ "Ventajas de Alloca". La biblioteca GNU C.
  2. ^ "En línea". Usando la colección de compiladores GNU (GCC) .
  3. ^ "Código fuente de Alloca.c [libiberty/Alloca.c] - Codebrowser".
  4. ^ alloca(3)  –  Manual del programador de Linux – Funciones de biblioteca
  5. ^ "¿Por qué el uso de alloca() no se considera una buena práctica?". stackoverflow.com . Consultado el 5 de enero de 2016 .
  6. ^ "_malloca". Documentación CRT de Microsoft .
  7. ^ "gnulib/malloca.h". GitHub . Consultado el 24 de noviembre de 2019 .
  8. ^ "glibc/include/alloca.h". Los espejos de Beren Minor. 23 de noviembre de 2019.
  9. ^ "Definición ISO C 99" (PDF) . Consultado el 10 de abril de 2022 .