En informática , la gestión manual de memoria se refiere al uso de instrucciones manuales por parte del programador para identificar y desasignar objetos no utilizados o basura . Hasta mediados de la década de 1990, la mayoría de los lenguajes de programación utilizados en la industria admitían la gestión manual de memoria, aunque la recolección de basura existe desde 1959, cuando se introdujo con Lisp . Hoy, sin embargo, los lenguajes con recolección de basura como Java son cada vez más populares y los lenguajes Objective-C y Swift proporcionan una funcionalidad similar a través del conteo automático de referencias . Los principales lenguajes administrados manualmente que todavía se usan ampliamente en la actualidad son C y C++ ; consulte Asignación dinámica de memoria en C.
Descripción
Muchos lenguajes de programación utilizan técnicas manuales para determinar cuándo asignar un nuevo objeto del almacén libre. C utiliza la mallocfunción; C++ y Java utilizan el newoperador; y muchos otros lenguajes (como Python) asignan todos los objetos del almacén libre. Determinar cuándo se debe crear un objeto ( creación de objetos ) es generalmente trivial y no problemático, aunque técnicas como los grupos de objetos significan que un objeto puede crearse antes de su uso inmediato. El verdadero desafío es la destrucción de objetos : determinar cuándo un objeto ya no es necesario (es decir, es basura) y organizar que su almacenamiento subyacente se devuelva al almacén libre para su reutilización. En la asignación manual de memoria, esto también lo especifica manualmente el programador; a través de funciones como free()en C, o el deleteoperador en C++; esto contrasta con la destrucción automática de objetos guardados en variables automáticas , en particular las variables locales (no estáticas) de funciones, que se destruyen al final de su alcance en C y C++.
Técnicas de gestión manual de memoria
Por ejemplo
- malloc/libre
- Arena de la memoria
- tampón de rayado
Gestión y corrección manual
Se sabe que la gestión manual de la memoria permite la aparición de varios tipos importantes de errores en un programa cuando se utiliza de forma incorrecta, en particular violaciones de la seguridad de la memoria o fugas de memoria . Estas son una fuente importante de errores de seguridad .
- Cuando un objeto no utilizado nunca se libera de nuevo al almacén libre, esto se conoce como pérdida de memoria . En algunos casos, las pérdidas de memoria pueden ser tolerables, como un programa que "pierde" una cantidad limitada de memoria durante su vida útil, o un programa de corta duración que depende de un sistema operativo para desasignar sus recursos cuando termina. Sin embargo, en muchos casos, las pérdidas de memoria ocurren en programas de larga duración y, en tales casos, se pierde una cantidad ilimitada de memoria. Cuando esto ocurre, el tamaño del almacén libre disponible continúa disminuyendo con el tiempo; cuando finalmente se agota, el programa se bloquea.
- Se puede producir un fallo catastrófico del sistema de gestión de memoria dinámica cuando se elimina la memoria de respaldo de un objeto más de una vez; se destruye explícitamente un objeto más de una vez; cuando, al utilizar un puntero para manipular un objeto que no está asignado en el almacenamiento libre, un programador intenta liberar la memoria de respaldo del objeto de destino de dicho puntero; o cuando, al manipular un objeto mediante un puntero a otra área arbitraria de memoria gestionada por una tarea, hilo o proceso externo desconocido, un programador corrompe el estado de ese objeto, posiblemente de tal manera que escriba fuera de sus límites y corrompa sus datos de gestión de memoria. El resultado de tales acciones puede incluir corrupción del montón , destrucción prematura de un objeto diferente (y recién creado) que ocupa la misma ubicación en la memoria que el objeto eliminado varias veces, fallos del programa debido a un fallo de segmentación (violación de la protección de la memoria ) y otras formas de comportamiento indefinido .
- Los punteros a objetos eliminados se convierten en punteros salvajes si se utilizan después de la eliminación; intentar utilizar dichos punteros puede generar errores difíciles de diagnosticar.
Se sabe que los lenguajes que utilizan exclusivamente la recolección de basura evitan las dos últimas clases de defectos. Aún pueden ocurrir fugas de memoria (y las fugas limitadas ocurren con frecuencia con la recolección de basura generacional o conservadora), pero generalmente son menos graves que las fugas de memoria en los sistemas manuales.
La adquisición de recursos es inicialización
La gestión manual de memoria tiene una ventaja de corrección, que es que permite la gestión automática de recursos a través del paradigma Adquisición de recursos es inicialización (RAII).
Esto ocurre cuando los objetos poseen recursos escasos del sistema (como recursos gráficos, manejadores de archivos o conexiones de bases de datos) que deben ser entregados cuando un objeto es destruido – cuando la vida útil de la propiedad del recurso debe estar ligada a la vida útil del objeto. Los lenguajes con administración manual pueden organizar esto adquiriendo el recurso durante la inicialización del objeto (en el constructor) y liberándolo durante la destrucción del objeto (en el destructor ), que ocurre en un momento preciso. Esto se conoce como Adquisición de recursos en inicialización.
Esto también se puede utilizar con el recuento de referencias determinista . En C++, esta capacidad se utiliza para automatizar la desasignación de memoria dentro de un marco que de otro modo sería manual; el uso de la shared_ptrplantilla en la biblioteca estándar del lenguaje para realizar la gestión de memoria es un paradigma común. Sin embargo, noshared_ptr es adecuado para todos los patrones de uso de objetos.
Este enfoque no se puede utilizar en la mayoría de los lenguajes de recolección de basura (especialmente en el rastreo de recolectores de basura o en el conteo de referencias más avanzado) debido a que la finalización no es determinista y, a veces, no ocurre en absoluto. Es decir, es difícil definir (o determinar) cuándo o si se puede llamar a un método finalizador ; esto se conoce comúnmente como el problema del finalizador. Java y otros lenguajes que implementan un recolector de basura con frecuencia utilizan la gestión manual de los escasos recursos del sistema además de la memoria a través del patrón dispose : se espera que cualquier objeto que administre recursos implemente el dispose()método, que libera dichos recursos y marca el objeto como inactivo. Se espera que los programadores invoquen dispose()manualmente según corresponda para evitar la "fuga" de recursos gráficos escasos. Para los recursos de pila (recursos adquiridos y liberados dentro de un solo bloque de código), esto se puede automatizar mediante varias construcciones de lenguaje, como -with-resources
de Python with, C# usingo Java .try
Actuación
Muchos defensores de la gestión manual de la memoria sostienen que ofrece un rendimiento superior en comparación con las técnicas automáticas, como la recolección de basura . Tradicionalmente, la latencia era la mayor ventaja, pero ya no es así. La asignación manual suele tener una localidad de referencia superior . [ cita requerida ]
También se sabe que la asignación manual es más apropiada para sistemas donde la memoria es un recurso escaso, debido a una recuperación más rápida. Los sistemas de memoria pueden "desestabilizarse" y, de hecho, lo hacen con frecuencia a medida que el tamaño del conjunto de trabajo de un programa se acerca al tamaño de la memoria disponible; los objetos no utilizados en un sistema con recolección de basura permanecen en un estado no recuperado durante más tiempo que en sistemas administrados manualmente, porque no se recuperan inmediatamente, lo que aumenta el tamaño efectivo del conjunto de trabajo.
La gestión manual tiene una serie de desventajas de rendimiento documentadas :
- Las llamadas a
deletey similares generan una sobrecarga cada vez que se realizan, que se puede amortizar en ciclos de recolección de basura. Esto es especialmente cierto en aplicaciones multiproceso, donde las llamadas de eliminación deben estar sincronizadas. - La rutina de asignación puede ser más complicada y más lenta. Algunos esquemas de recolección de basura, como aquellos con compactación de montón , pueden mantener el almacenamiento libre como una matriz simple de memoria (a diferencia de las implementaciones complicadas que requieren los esquemas de administración manual).
La latencia es un punto de debate que ha cambiado con el tiempo: los primeros recolectores de basura y las implementaciones simples tenían un rendimiento muy deficiente en comparación con la administración manual de memoria, pero los recolectores de basura modernos y sofisticados a menudo funcionan tan bien o mejor que la administración manual de memoria. [ cita requerida ]
La asignación manual no sufre los largos tiempos de "pausa" que ocurren en la recolección de basura simple de "detener el mundo", aunque los recolectores de basura modernos tienen ciclos de recolección que a menudo no son perceptibles. [ cita requerida ]
Tanto la gestión manual de memoria como la recolección de basura sufren de tiempos de desasignación potencialmente ilimitados: la gestión manual de memoria porque desasignar un solo objeto puede requerir desasignar sus miembros y, recursivamente, los miembros de sus miembros, etc., mientras que la recolección de basura puede tener ciclos de recolección largos. Esto es especialmente un problema en sistemas de tiempo real , donde los ciclos de recolección ilimitados son generalmente inaceptables; la recolección de basura en tiempo real es posible pausando el recolector de basura, mientras que la gestión manual de memoria en tiempo real requiere evitar grandes desasignaciones o pausar manualmente la desasignación.
Referencias
- Berger, ED; Zorn, BG; McKinley, KS (noviembre de 2002). "Reconsideración de 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.
Véase también
Enlaces externos
- La referencia de gestión de memoria
- Richard Jones y Rafael Lins, Recolección de basura: algoritmos para la gestión automatizada de la memoria dinámica , Wiley and Sons (1996), ISBN 0-471-94148-4