La gestión de memoria (también conocida como gestión dinámica de memoria , asignación dinámica de almacenamiento o asignación dinámica de memoria ) es una forma de gestión de recursos aplicada a la memoria de la computadora . El requisito esencial de la gestión de memoria es proporcionar mecanismos para asignar dinámicamente porciones de memoria a los programas según sus necesidades y liberarlas para su reutilización cuando ya no sean necesarias. Esto es fundamental para cualquier sistema informático avanzado donde más de un proceso pueda estar en ejecución simultáneamente ( multitarea ). [ 1 ]
Se han ideado varios métodos para aumentar la eficacia de la gestión de memoria. Los sistemas de memoria virtual separan las direcciones de memoria utilizadas por un proceso de las direcciones físicas reales, lo que permite la separación de procesos y el aumento del espacio de direcciones virtuales más allá de la cantidad de RAM disponible mediante paginación o intercambio a almacenamiento secundario . La calidad del gestor de memoria virtual puede tener un efecto considerable en el rendimiento general del sistema . El sistema permite que un ordenador parezca tener más memoria disponible de la que realmente tiene, lo que permite que múltiples procesos la compartan.
En algunos sistemas operativos , por ejemplo Burroughs/Unisys MCP , [ 2 ] y OS/360 y sus sucesores , [ 3 ] la memoria es administrada por el sistema operativo. [ nota 1 ] En otros sistemas operativos, por ejemplo, los sistemas operativos tipo Unix , la memoria se administra a nivel de aplicación.
La gestión de la memoria dentro de un espacio de direcciones se clasifica generalmente como gestión manual de la memoria o gestión automática de la memoria.
Gestión manual de la memoria

La tarea de satisfacer una solicitud de asignación consiste en localizar un bloque de memoria no utilizada de tamaño suficiente. Las solicitudes de memoria se satisfacen asignando porciones de un gran conjunto [ nota 2 ] de memoria llamado montón [ nota 3 ] o almacenamiento libre . En cualquier momento dado, algunas partes del montón están en uso, mientras que otras están "libres" (no utilizadas) y, por lo tanto, disponibles para futuras asignaciones. En el lenguaje C, la función que asigna memoria del montón se llama mallocy la función que toma la memoria previamente asignada y la marca como "libre" (para ser utilizada por futuras asignaciones) se llama free. [ nota 4 ]
Diversos problemas complican la implementación, como la fragmentación externa , que surge cuando existen muchos espacios pequeños entre los bloques de memoria asignados, lo que invalida su uso para una solicitud de asignación. Los metadatos del asignador también pueden aumentar el tamaño de las asignaciones (individualmente) pequeñas. Esto suele gestionarse mediante la segmentación . El sistema de gestión de memoria debe realizar un seguimiento de las asignaciones pendientes para garantizar que no se superpongan y que nunca se "pierda" memoria (es decir, que no haya " fugas de memoria ").
Eficiencia
El algoritmo específico de asignación dinámica de memoria implementado puede afectar significativamente el rendimiento. Un estudio realizado en 1994 por Digital Equipment Corporation ilustra la sobrecarga involucrada para una variedad de asignadores. La longitud promedio más baja de la ruta de instrucción requerida para asignar una sola ranura de memoria fue de 52 (medida con un perfilador de nivel de instrucción en varios programas). [ 1 ]
Implementaciones
Dado que la ubicación precisa de la asignación no se conoce de antemano, se accede a la memoria indirectamente, generalmente a través de una referencia de puntero . El algoritmo específico utilizado para organizar el área de memoria y asignar y liberar bloques está interconectado con el núcleo y puede utilizar cualquiera de los siguientes métodos:
Asignación de bloques de tamaño fijo
La asignación de bloques de tamaño fijo, también llamada asignación de memoria en grupo, utiliza una lista libre de bloques de memoria de tamaño fijo (generalmente todos del mismo tamaño). Esto funciona bien para sistemas embebidos sencillos donde no se necesitan asignar objetos grandes, pero sufre de fragmentación , especialmente con direcciones de memoria largas. Sin embargo, debido a la significativa reducción de la sobrecarga, este método puede mejorar sustancialmente el rendimiento para objetos que necesitan asignación y liberación frecuentes, por lo que se usa a menudo en videojuegos .
Bloques de amigos
En este sistema, la memoria se asigna a varios grupos de memoria en lugar de a uno solo, donde cada grupo representa bloques de memoria de un tamaño que es una potencia de dos , o bloques con alguna otra progresión de tamaño conveniente. Todos los bloques de un tamaño determinado se almacenan en una lista o árbol enlazado ordenado , y todos los bloques nuevos que se forman durante la asignación se agregan a sus respectivos grupos de memoria para su uso posterior. Si se solicita un tamaño menor al disponible, se selecciona el tamaño disponible más pequeño y se divide. Cuando un bloque se divide, se divide en dos bloques más pequeños, y cada bloque más pequeño se convierte en un "compañero" único del otro. Se selecciona una de las partes resultantes y el proceso se repite hasta que se completa la solicitud. Cuando se asigna un bloque, el asignador comenzará con el bloque más pequeño suficientemente grande para evitar la división innecesaria de bloques. Cuando se libera un bloque, se compara con su compañero. Si ambos están libres, se combinan y se colocan en la lista de bloques compañeros de mayor tamaño correspondiente.
Asignación de losas
Este mecanismo de asignación de memoria preasigna bloques de memoria adecuados para objetos de un tipo o tamaño determinado. [ 5 ] Estos bloques se denominan cachés, y el asignador solo tiene que mantener un registro de la lista de ranuras de caché libres. La creación de un objeto utilizará cualquiera de las ranuras de caché libres, y la destrucción de un objeto añadirá una ranura a la lista de ranuras de caché libres. Esta técnica reduce la fragmentación de la memoria y es eficiente, ya que no es necesario buscar una porción de memoria adecuada, pues cualquier ranura libre es suficiente.
Asignación de pila
Muchos sistemas tipo Unix, así como Microsoft Windows, implementan una función allocapara asignar dinámicamente memoria de pila de forma similar a la asignación basada en el montón malloc. Un compilador normalmente la traduce a instrucciones en línea que manipulan el puntero de pila. [ 6 ] Aunque no es necesario liberar manualmente la memoria asignada de esta manera, ya que se libera automáticamente cuando la función que la llamó allocaregresa, existe el riesgo de desbordamiento. Y dado que `alloca` es una expansión ad hoc que se ve en muchos sistemas pero nunca en POSIX ni en el estándar C, su comportamiento en caso de desbordamiento de pila es indefinido.
Existe una versión más segura de alloca llamada _malloca, que informa errores, en Microsoft Windows. Requiere el uso de _freea. [ 7 ] gnulib proporciona una interfaz equivalente, aunque en lugar de lanzar una excepción SEH en caso de desbordamiento, delega a malloc cuando se detecta un tamaño demasiado grande. [ 8 ] Se puede emular una característica similar utilizando contabilidad manual y comprobación de tamaño, como en los usos de alloca_accounten glibc. [ 9 ]
Gestión automatizada de la memoria
La gestión adecuada de la memoria en una aplicación es un problema difícil, y se han ideado varias estrategias diferentes para abordar la gestión de la memoria.
Gestión automática de las variables de la pila de llamadas
En muchas implementaciones de lenguajes de programación, el entorno de ejecución asigna automáticamente memoria en la pila de llamadas para las variables locales no estáticas de una subrutina , denominadas variables automáticas , cuando se llama a la subrutina, y libera automáticamente esa memoria cuando se sale de ella. Declaraciones especiales pueden permitir que las variables locales conserven sus valores entre invocaciones del procedimiento, o que otras subrutinas accedan a ellas. La asignación automática de variables locales posibilita la recursión , con una profundidad limitada por la memoria disponible.
Recogida de basura
La recolección de basura es una estrategia para detectar automáticamente la memoria asignada a objetos que ya no se pueden usar en un programa y devolverla a un grupo de ubicaciones de memoria libres. Este método contrasta con la gestión de memoria "manual", donde el programador codifica explícitamente las solicitudes y liberaciones de memoria en el programa. Si bien la recolección de basura automática tiene la ventaja de reducir la carga de trabajo del programador y prevenir ciertos tipos de errores de asignación de memoria, también requiere recursos de memoria propios y puede competir con el programa de aplicación por el tiempo del procesador.
Conteo de referencias
El conteo de referencias es una estrategia para detectar que una memoria ya no está disponible para un programa, mediante el mantenimiento de un contador que indica cuántos punteros independientes apuntan a ella. Cada vez que un nuevo puntero apunta a una porción de memoria, el programador debe incrementar el contador. Cuando el puntero cambia de ubicación, deja de apuntar a cualquier área o se libera, el contador disminuye. Cuando el contador llega a cero, la memoria se considera no utilizada y se libera. Algunos sistemas de conteo de referencias requieren la intervención del programador, mientras que otros son implementados automáticamente por el compilador. Una desventaja del conteo de referencias es que pueden generarse referencias circulares , lo que provoca fugas de memoria. Esto se puede mitigar añadiendo el concepto de " referencia débil " (una referencia que no participa en el conteo de referencias, pero que recibe una notificación cuando el área a la que apunta ya no es válida) o combinando el conteo de referencias con la recolección de basura.
grupos de memoria
Un pool de memoria es una técnica para liberar automáticamente la memoria en función del estado de la aplicación, como el ciclo de vida de una solicitud o transacción. La idea es que muchas aplicaciones ejecutan grandes bloques de código que pueden generar asignaciones de memoria, pero que llega un punto en la ejecución en el que se sabe que todos esos bloques ya no son necesarios. Por ejemplo, en un servicio web, después de cada solicitud, el servicio ya no necesita la memoria asignada durante su ejecución. Por lo tanto, en lugar de controlar si la memoria está siendo referenciada o no, se asigna según la solicitud o la etapa del ciclo de vida con la que está asociada. Cuando esa solicitud o etapa ha finalizado, toda la memoria asociada se libera simultáneamente.
Sistemas con memoria virtual
La memoria virtual es un método para desacoplar la organización de la memoria del hardware físico. Las aplicaciones operan en la memoria mediante direcciones virtuales . Cada intento de la aplicación de acceder a una dirección de memoria virtual específica da como resultado que dicha dirección se traduzca a una dirección física real . [ 10 ] De esta manera, la adición de memoria virtual permite un control granular sobre los sistemas de memoria y los métodos de acceso.
En los sistemas de memoria virtual, el sistema operativo limita el acceso de un proceso a la memoria. Esta función, denominada protección de memoria , impide que un proceso lea o escriba en memoria que no le ha sido asignada, evitando así que código malicioso o defectuoso de un programa interfiera con el funcionamiento de otro.
Aunque la memoria asignada a procesos específicos suele estar aislada, a veces los procesos necesitan compartir información. La memoria compartida es una de las técnicas más rápidas para la comunicación entre procesos .
La memoria se suele clasificar, según su tasa de acceso, en almacenamiento primario y almacenamiento secundario . Los sistemas de gestión de memoria, entre otras operaciones, también se encargan de la transferencia de información entre estos dos niveles de memoria.
Gestión de memoria en sistemas MCP de Burroughs/Unisys [ 2 ]
Un sistema operativo gestiona diversos recursos del sistema informático. El subsistema de memoria es el elemento del sistema encargado de gestionar la memoria. Este subsistema combina el recurso de memoria del hardware con el software del sistema operativo MCP que gestiona dicho recurso.
El subsistema de memoria gestiona la memoria física y la memoria virtual del sistema (ambas forman parte del hardware). La memoria virtual amplía la memoria física utilizando espacio adicional en un dispositivo periférico, generalmente un disco. El subsistema de memoria se encarga de mover código y datos entre la memoria principal y la virtual en un proceso conocido como superposición. Burroughs fue la primera implementación comercial de memoria virtual (aunque desarrollada en la Universidad de Manchester para el ordenador Ferranti Atlas) e integró la memoria virtual en el diseño del sistema B5000 desde el principio (en 1961), sin necesidad de una unidad de gestión de memoria (MMU) externa. [ 11 ] : 48
El subsistema de memoria se encarga de asignar las solicitudes lógicas de bloques de memoria a porciones físicas de memoria (segmentos) que se encuentran en la lista de segmentos libres. Cada bloque asignado se gestiona mediante un descriptor de segmento, [ 12 ] una palabra de control especial que contiene metadatos relevantes sobre el segmento, incluyendo la dirección, la longitud, el tipo de máquina y el bit p o bit de 'presencia' que indica si el bloque está en la memoria principal o si necesita cargarse desde la dirección dada en el descriptor.
Los descriptores son esenciales para garantizar la seguridad de la memoria, de modo que las operaciones no puedan desbordar ni subdesbordar el bloque referenciado (lo que comúnmente se conoce como desbordamiento de búfer). Los descriptores son palabras de control protegidas que no pueden ser manipuladas, excepto por elementos específicos del sistema operativo MCP (habilitados por la directiva de bloque UNSAFE en NEWP ).
Donald Knuth describe un sistema similar en la Sección 2.5 'Asignación dinámica de almacenamiento' de 'Algoritmos fundamentales' .
Gestión de memoria en OS/360 y sus sucesores
IBM System/360 no admite memoria virtual. [ nota 5 ] El aislamiento de memoria de los trabajos se realiza opcionalmente mediante claves de protección , asignando a cada trabajo una clave diferente: 0 para el supervisor o 1–15. La gestión de memoria en OS/360 es una función del supervisorGETMAIN . El almacenamiento se solicita mediante la macro y se libera mediante la FREEMAINmacro, lo que da como resultado una llamada al supervisor ( SVC ) para realizar la operación.
En OS/360 los detalles varían dependiendo de cómo se genere el sistema , por ejemplo, para PCP , MFT , MVT .
En OS/360 MVT, la subasignación dentro de la región de un trabajo o el Área de Cola del Sistema (SQA) compartida se basa en subgrupos , áreas de un tamaño múltiplo de 2 KB, el tamaño de un área protegida por una clave de protección. Los subgrupos están numerados del 0 al 255. [ 13 ] Dentro de una región, a los subgrupos se les asigna la protección de almacenamiento del trabajo o la clave del supervisor, clave 0. Los subgrupos del 0 al 127 reciben la clave del trabajo. Inicialmente, solo se crea el subgrupo cero, y todas las solicitudes de almacenamiento del usuario se satisfacen desde el subgrupo 0, a menos que se especifique otro en la solicitud de memoria. Los subgrupos del 250 al 255 son creados por solicitudes de memoria del supervisor en nombre del trabajo. A la mayoría de estos se les asigna la clave 0, aunque algunos obtienen la clave del trabajo. Los números de subgrupo también son relevantes en MFT, aunque los detalles son mucho más simples. [ 14 ] MFT utiliza particiones fijas redefinibles por el operador en lugar de regiones dinámicas y PCP tiene solo una partición.
Cada subgrupo se representa mediante una lista de bloques de control que identifican los bloques de memoria asignados y libres dentro del subgrupo. La memoria se asigna encontrando un área libre de tamaño suficiente o asignando bloques adicionales en el subgrupo, hasta alcanzar el tamaño de la región del trabajo. Es posible liberar total o parcialmente un área de memoria asignada. [ 15 ]
Los detalles para OS/VS1 son similares [ 16 ] a los de MFT y MVT; los detalles para OS/VS2 son similares a los de MVT, excepto que el tamaño de página es de 4 KiB. Tanto para OS/VS1 como para OS/VS2, el área de cola del sistema compartida (SQA) no es paginable.
En MVS, el espacio de direcciones [ 17 ] incluye un área compartida paginable adicional, el Área de Almacenamiento Común (CSA), y dos áreas privadas adicionales: el área de cola del sistema local no paginable (LSQA) y el área de trabajo del sistema paginable (SWA). Además, las claves de almacenamiento 0 a 7 están reservadas para uso del código privilegiado.
Véase también
Notas
- ↑ Sin embargo, el entorno de ejecución de un procesador de lenguaje puede subdividir dinámicamente la memoria adquirida del sistema operativo, por ejemplo, para implementar una pila.
- ↑ En algunos sistemas operativos, por ejemplo, OS/360 , el almacenamiento libre puede subdividirse de varias maneras, por ejemplo, subgrupos en OS/360 , debajo de la línea, encima de la línea y encima de la barra en z/OS .
- ↑ No confundir con laestructura de datos de montón , que no guarda relación con la anterior.
- ↑ Una implementación simplificada de estas dos funciones se puede encontrar en el artículo "Inside Memory Management". [ 4 ]
- ↑ Excepto en el modelo 67
Referencias
- 1 2 Detlefs, D.; Dosser, A.; Zorn, B. (junio de 1994). "Costos de asignación de memoria en programas grandes de C y C++" (PDF) . Software: Practice and Experience . 24 (6): 527– 542. CiteSeerX 10.1.1.30.3073 . doi : 10.1002/spe.4380240602 . S2CID 14214110 .
- 1 2 "Unisys MCP Administración de memoria" . Guía de operaciones del sistema . Unisys .
- ↑ "Asignación de almacenamiento principal" (PDF) . Conceptos y funciones del sistema operativo IBM/360 (PDF) . Biblioteca de referencia de sistemas IBM (primera edición). IBM Corporation. 1965. pág. 74. Consultado el 3 de abril de 2019 .
- ↑ Jonathan Bartlett. "Gestión de memoria interna" . IBM DeveloperWorks .
- ↑ Silberschatz, Abraham ; Galvin, Peter B. (2004). Conceptos de sistemas operativos . Wiley. ISBN 0-471-69466-5.
- ↑ – Manual del programador de Linux – Funciones de la biblioteca
- ↑ "_malloca" . Documentación de Microsoft CRT . 26 de octubre de 2022.
- ↑ "gnulib/malloca.h" . GitHub . Consultado el 24 de noviembre de 2019 .
- ↑ "glibc/include/alloca.h" . Espejos de Beren Minor. 23 de noviembre de 2019.
- ↑ Tanenbaum, Andrew S. (1992). Sistemas operativos modernos . Englewood Cliffs, NJ: Prentice-Hall. pág. 90. ISBN 0-13-588187-0.
- ↑ Waychoff, Richard. "Historias sobre el B5000 y las personas que estuvieron allí" (PDF) . Museo de Historia de la Computación .
- ↑ El Descriptor (PDF) . Burroughs Corporation . Febrero de 1961.
- ↑ OS360Sup , págs. 82–85 .
- ↑ OS360Sup , págs. 82 .
- ↑ Lógica del programa: Supervisor MVT del sistema operativo IBM System/360 (PDF) . IBM Corporation. Mayo de 1973. págs. 107–137 . Consultado el 3 de abril de 2019 .
- ↑ OSVS1Dig , págs. 2.37-2.39 .
- ↑ "Diseño de almacenamiento virtual" (PDF) . Introducción a OS/VS2 Release 2 (PDF) . Sistemas (primera ed.). IBM . Marzo de 1973. pág. 37. GC28-0661-1 . Consultado el 15 de julio de 2024 .
Bibliografía
- Donald Knuth . Algoritmos fundamentales , tercera edición. Addison-Wesley, 1997. ISBN 0-201-89683-4. Sección 2.5: Asignación dinámica de almacenamiento, págs. 435–456.
- Algoritmos sencillos de asignación de memoria archivados el 5 de marzo de 2016 en Wayback Machine (publicado originalmente en OSDEV Community).
- Wilson, PR; Johnstone, MS; Neely, M.; Boles, D. (1995). "Asignación dinámica de almacenamiento: una revisión y análisis crítico" (PDF) . Memory Management . Lecture Notes in Computer Science. Vol. 986. pp. 1–116 . CiteSeerX 10.1.1.47.275 . doi : 10.1007/3-540-60368-9_19 . ISBN 978-3-540-60368-9.
- Berger, ED; Zorn, BG; McKinley, KS (junio de 2001). «Composición de asignadores de memoria de alto rendimiento» (PDF) . Actas de la conferencia ACM SIGPLAN 2001 sobre diseño e implementación de lenguajes de programación . PLDI '01. págs. 114–124 . CiteSeerX 10.1.1.1.2112 . doi : 10.1145/378795.378821 . ISBN 1-58113-414-2. S2CID 7501376 .
- Berger, ED; Zorn, BG; McKinley, KS (noviembre de 2002). «Reconsiderando la asignación de memoria personalizada» (PDF) . Actas de la 17.ª conferencia ACM SIGPLAN sobre programación orientada a objetos, sistemas, lenguajes y aplicaciones . OOPSLA '02. págs. 1-12 . CiteSeerX 10.1.1.119.5298 . doi : 10.1145/582419.582421 . ISBN 1-58113-471-1. S2CID 481812 .
- OS360Sup
- Servicios de supervisión e instrucciones macro del sistema operativo IBM System/360, versión 21 (PDF) . Biblioteca de referencia de sistemas IBM (octava edición). IBM . Septiembre de 1974. GC28-6646-7.
- OSVS1Dig
- OS/VS1 Programmer's Reference Digest Release 6 (PDF) . Sistemas (Sexta ed.). IBM . 15 de septiembre de 1976. GC24-5091-5 con TNL.
Enlaces externos
- Biblioteca C++ "Administrador de memoria genérico"
- Ejemplo de asignador de memoria de área de aplicación de mapas de bits en C
- TLSF: un asignador de tiempo constante para sistemas en tiempo real.
- Diapositivas sobre asignación dinámica de memoria
- Dentro de un asignador de almacenamiento
- Referencia de gestión de memoria
- Referencia de gestión de memoria, Guía para principiantes sobre asignación de memoria
- Gestión de memoria en Linux
- Gestión de memoria para programadores de sistemas
- VMem: reemplazo general para malloc/free. Asignador de memoria rápido y seguro para subprocesos en C++.
- Gestión de la memoria del sistema operativo
- Gestión de la memoria
- Arquitectura de computadoras