Gestión de la memoria
Administración de memoria es una forma de administración de recursos aplicada a la memoria de la computadora. El requisito esencial de la gestión de la memoria es proporcionar formas de asignar dinámicamente porciones de memoria a los programas que lo soliciten y liberarla para su reutilización cuando ya no se necesite. Esto es fundamental para cualquier sistema informático avanzado en el que pueda estar en marcha más de un proceso en cualquier momento.
Se han ideado varios métodos que aumentan la eficacia de la gestión de la 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 aumenta el tamaño del espacio de direcciones virtuales más allá de la cantidad disponible de RAM mediante paginación o intercambio a almacenamiento secundario. La calidad del administrador de memoria virtual puede tener un efecto importante en el rendimiento general del sistema.
En algunos sistemas operativos, p. OS/360 y sucesores, la memoria es administrada por el sistema operativo. En otros sistemas operativos, p. En los sistemas operativos similares a Unix, la memoria se administra a nivel de aplicación.
La administración de memoria dentro de un espacio de direcciones generalmente se clasifica como administración de memoria manual o administración de memoria automática.
Gestión de memoria manual
La tarea de cumplir con una solicitud de asignación consiste en ubicar un bloque de memoria no utilizada de tamaño suficiente. Las solicitudes de memoria se satisfacen mediante la asignación de porciones de un gran grupo de memoria llamado montón o almacén libre. En un momento dado, algunas partes del montón están en uso, mientras que otras son "gratuitas" (sin usar) y, por lo tanto, disponible para asignaciones futuras.
Varios problemas complican la implementación, como la fragmentación externa, que surge cuando hay 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 inflar el tamaño de asignaciones pequeñas (individualmente). Esto a menudo se gestiona mediante fragmentación. El sistema de administración de memoria debe realizar un seguimiento de las asignaciones pendientes para garantizar que no se superpongan y que nunca se "pierda" ninguna memoria. (es decir, que no hay "pérdidas de memoria").
Eficiencia
El algoritmo de asignación de memoria dinámica específico implementado puede afectar significativamente el rendimiento. Un estudio realizado en 1994 por Digital Equipment Corporation ilustra los gastos generales involucrados para una variedad de asignadores. La longitud de ruta de instrucción promedio más baja requerida para asignar una sola ranura de memoria fue 52 (medida con un perfilador de nivel de instrucción en una variedad de software).
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 desasignar fragmentos 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 grupo de memoria, utiliza una lista libre de bloques de memoria de tamaño fijo (a menudo todos del mismo tamaño). Esto funciona bien para sistemas integrados simples donde no es necesario asignar objetos grandes, pero sufre fragmentación, especialmente con direcciones de memoria largas. Sin embargo, debido a la sobrecarga significativamente reducida, este método puede mejorar sustancialmente el rendimiento de los objetos que necesitan una asignación/desasignación frecuente y, a menudo, se usa en videojuegos.
Bloques de amigos
En este sistema, la memoria se asigna en varios grupos de memoria en lugar de solo uno, donde cada grupo representa bloques de memoria de un cierto tamaño de potencia de dos, o bloques de alguna otra progresión de tamaño conveniente. Todos los bloques de un tamaño particular se mantienen en una lista ordenada o en un árbol 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 más pequeño que el disponible, se selecciona y se divide el tamaño más pequeño disponible. 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 lo suficientemente grande para evitar romper bloques innecesariamente. 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 bloque de amigos de mayor tamaño correspondiente.
Asignación de losas
Este mecanismo de asignación de memoria preasigna fragmentos de memoria adecuados para adaptarse a objetos de cierto tipo o tamaño. Estos fragmentos se denominan cachés y el asignador solo tiene que realizar un seguimiento de una lista de ranuras de caché libres. La construcción de un objeto utilizará cualquiera de las ranuras de caché libres y la destrucción de un objeto agregará una ranura de nuevo a la lista de ranuras de caché libres. Esta técnica alivia la fragmentación de la memoria y es eficiente ya que no hay necesidad de buscar una porción adecuada de la memoria, ya que cualquier ranura abierta será suficiente.
Asignación de pilas
Muchos sistemas similares a Unix, así como Microsoft Windows, implementan una función llamada alloca
para asignar dinámicamente la memoria de la pila de una manera similar a la basada en montón malloc
. Un compilador normalmente lo traduce a instrucciones en línea que manipulan el puntero de la pila. Aunque no hay necesidad de liberar manualmente la memoria asignada de esta manera, ya que se libera automáticamente cuando la función que llamó alloca
devuelve, existe riesgo de desbordamiento. Y dado que alloca es una expansión ad hoc vista en muchos sistemas pero nunca en POSIX o el estándar C, su comportamiento en caso de un desbordamiento de pila no está definido.
Una versión más segura de alloca llamada _malloca
, que informa errores, existe en Microsoft Windows. Requiere el uso de _freea
. gnulib proporciona una interfaz equivalente, aunque en lugar de lanzar una excepción SEH en caso de desbordamiento, delega en malloc cuando se detecta un tamaño demasiado grande. Se puede emular una característica similar utilizando contabilidad manual y verificación de tamaño, como en los usos de alloca_account
en glibc.
Gestión automática de memoria
En muchas implementaciones de lenguajes de programación, el entorno de tiempo de ejecución del programa asigna automáticamente memoria en la pila de llamadas para variables locales no estáticas de una subrutina, llamadas variables automáticas, cuando se llama a la subrutina, y automáticamente libera esa memoria cuando la subrutina se sale. Las declaraciones especiales pueden permitir que las variables locales retengan valores entre invocaciones del procedimiento, o pueden permitir que otras subrutinas accedan a las variables locales. La asignación automática de variables locales hace posible la recursividad, hasta una profundidad limitada por la memoria disponible.
Recolección de basura
La recolección de elementos no utilizados es una estrategia para detectar automáticamente la memoria asignada a objetos que ya no se pueden usar en un programa y devolver esa memoria asignada a un conjunto de ubicaciones de memoria libres. Este método contrasta con el "manual" gestión de memoria donde un programador codifica explícitamente solicitudes de memoria y liberaciones de memoria en el programa. Si bien la recolección de basura automática tiene las ventajas de reducir la carga de trabajo del programador y evitar ciertos tipos de errores de asignación de memoria, la recolección de basura requiere recursos de memoria propios y puede competir con el programa de aplicación por el tiempo del procesador.
Sistemas con memoria virtual
La memoria virtual es un método para desvincular la organización de la memoria del hardware físico. Las aplicaciones operan en la memoria a través de direcciones virtuales. Cada intento de la aplicación de acceder a una dirección de memoria virtual en particular da como resultado que la dirección de memoria virtual se traduzca a una dirección física real. De esta forma, 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 la forma en que un proceso puede acceder a la memoria. Esta característica, llamada protección de memoria, se puede utilizar para impedir que un proceso lea o escriba en la memoria que no se le ha asignado, evitando que el código malicioso o que funciona mal en un programa interfiera con el funcionamiento de otro.
Aunque la memoria asignada para procesos específicos normalmente está aislada, a veces los procesos necesitan poder compartir información. La memoria compartida es una de las técnicas más rápidas para la comunicación entre procesos.
La memoria generalmente se clasifica por tasa de acceso en almacenamiento primario y almacenamiento secundario. Los sistemas de administración de memoria, entre otras operaciones, también manejan el movimiento de información entre estos dos niveles de memoria.
Gestión de memoria en OS/360 y sucesores
IBM System/360 no admite memoria virtual. El aislamiento de la memoria de los trabajos se logra opcionalmente usando claves de protección, asignando almacenamiento para cada trabajo con una clave diferente, 0 para el supervisor o 1-15. La gestión de memoria en OS/360 es una función de supervisor. El almacenamiento se solicita mediante la macro GETMAIN
y se libera mediante la macro FREEMAIN
, lo que da como resultado una llamada al supervisor (SVC) para realizar la operación.
En OS/360, los detalles varían según 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. Dentro de una región, a los subgrupos se les asigna la protección de almacenamiento del trabajo o la clave del supervisor, la clave 0. Los subgrupos 0–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 250–255 se crean mediante 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 subgrupos también son relevantes en MFT, aunque los detalles son mucho más simples. MFT usa particiones fijas redefinibles por el operador en lugar de regiones dinámicas y PCP tiene una sola partición.
Cada subgrupo se asigna 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 el tamaño de la región del trabajo. Es posible liberar todo o parte de un área de memoria asignada.
Los detalles de OS/VS1 son similares a los de MFT y MVT; los detalles de 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 (SQA) compartida no es paginable.
En MVS, el espacio de direcciones incluye un área compartida paginable adicional, el Área de almacenamiento común (CSA), y un área privada adicional, el Área de trabajo del sistema (SWA). Además, las claves de almacenamiento 0-7 están reservadas para su uso por código privilegiado.
Contenido relacionado
Cobertura de código
Operador bastardo del infierno
Navegador