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 pila apunta al dato superior actual en la pila. Una operación push decrementa el puntero y copia los datos a la pila; una operación pop 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 memoria donde se agregan o eliminan datos según el método "último en entrar, primero en salir" (LIFO) .

En la mayoría de los sistemas informáticos modernos, cada subproceso tiene una región reservada de memoria 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 subproceso se utiliza para almacenar la ubicación de una dirección de retorno proporcionada por el llamador para permitir que las instrucciones de retorno regresen a la ubicación correcta.

La pila se utiliza a menudo para almacenar variables de longitud fija locales para las funciones activas en ese momento. 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 hilo, 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). La SBMA a menudo está estrechamente acoplada con una pila de llamadas de función .

Ventajas y desventajas

Debido a que los datos se agregan y eliminan de manera tal que "el último en entrar es el primero en salir", la asignación de memoria basada en pila es muy simple y, por lo general, 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, en C.malloc

Otra característica es que la memoria en la pila se recupera automáticamente y de manera muy eficiente 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 en alguna forma, entonces deben copiarse de la pila al montón antes de que la función salga. Por lo tanto, la asignación basada en la pila es adecuada para datos temporales o datos que ya no son necesarios después de que la función actual sale.

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 a un desbordamiento de pilaalloca . Esta es también la razón por la que se suele impedir que se incorporen funciones que usan : [2] si se incorporen funciones de este tipo a un bucle, el invocador sufriría un crecimiento imprevisto en el uso de la pila, lo que haría que un desbordamiento fuera mucho más probable.

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 tanto los punteros de pila como de marco deben administrarse (con marcos de pila de tamaño fijo, el puntero de pila es redundante debido a la multiplicación del puntero de marco de pila por el tamaño de cada marco). Esto suele ser mucho menos costoso que llamar malloca y freede todos modos. En particular, si la función actual contiene tanto llamadas a allocacomo bloques que contienen datos locales de longitud variable, entonces ocurre un conflicto entre los intentos de alloca de aumentar el marco de pila actual hasta que la función actual salga frente a la necesidad del compilador de colocar variables locales de longitud variable en la misma ubicación en el marco de pila. Este conflicto normalmente se resuelve creando una cadena separada de almacenamiento de montón para cada llamada a alloca. [3] La cadena registra la profundidad de pila en la que se produce cada asignación, las llamadas posteriores a allocaen cualquier función recortan esta cadena a la profundidad de pila actual para eventualmente (pero no inmediatamente) liberar cualquier almacenamiento en esta cadena. Una llamada a allocacon un argumento de cero también se puede utilizar para activar la liberación de memoria sin asignar más memoria de ese tipo. Como consecuencia de este conflicto entre allocay el almacenamiento de variables locales, usar allocapodría no ser más eficiente que usar malloc.

Interfaz del sistema

Muchos sistemas similares a 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 heap malloc. Un compilador normalmente la traduce a instrucciones en línea que manipulan el puntero de pila, de manera similar a cómo se manejan las matrices de longitud variable . [4] Aunque no hay necesidad de liberar explícitamente la memoria, existe el riesgo de un comportamiento indefinido debido al desbordamiento de pila. [5] La función estaba presente en sistemas Unix desde 32/V (1978), pero no es parte del estándar C ni de ningún estándar POSIX .

En Microsoft Windows existe una versión más segura de allocacalled , que asigna en el montón si el tamaño de asignación es demasiado grande y reporta errores de desbordamiento de pila. Requiere el uso de . [6] gnulib proporciona una interfaz equivalente, aunque en lugar de lanzar una excepción SEH en caso de desbordamiento, delega a cuando 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 en glibc. [8]_malloca_freea mallocalloca_account

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

VLA automáticos

Además, desde la versión 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 ( variable-length array ). [9]

void f ( int arrayLength ) { int b [ arrayLength ]; // VLA automático: 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(). }                    

Véase también

Referencias

  1. ^ "Ventajas de Alloca". La biblioteca C de GNU .
  2. ^ "En línea". Uso de 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 la biblioteca
  5. ^ "¿Por qué no se considera una buena práctica el uso de alloca()?". stackoverflow.com . Consultado el 5 de enero de 2016 .
  6. ^ "_malloca". Documentación de Microsoft CRT .
  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 .