stringtranslate.com

Gestión de memoria clásica de Mac OS

Ventana "Acerca de este equipo" de Mac OS 9.1 que muestra el consumo de memoria de cada aplicación abierta y el software del sistema en sí

Históricamente, el sistema operativo Mac OS clásico utilizaba una forma de gestión de memoria que ha caído en desuso en los sistemas modernos. Las críticas a este enfoque fueron una de las áreas clave que se abordaron con el cambio a Mac OS X.

El problema original para los ingenieros de Macintosh era cómo hacer un uso óptimo de los 128 KB de RAM con los que estaba equipada la máquina, en un hardware informático basado en Motorola 68000 que no soporta memoria virtual . [1] Dado que en ese momento la máquina solo podía ejecutar un programa de aplicación a la vez, y no había almacenamiento secundario fijo , los ingenieros implementaron un esquema simple que funcionó bien con esas restricciones particulares. Esa elección de diseño no escaló bien con el desarrollo de la máquina, creando varias dificultades tanto para los programadores como para los usuarios.

Fragmentación

La principal preocupación de los ingenieros originales parece haber sido la fragmentación , es decir, la asignación y desasignación repetida de memoria a través de punteros que conducen a muchas áreas pequeñas y aisladas de memoria que no se pueden usar porque son demasiado pequeñas, aunque la memoria libre total puede ser suficiente para satisfacer una solicitud particular de memoria. Para resolver esto, los ingenieros de Apple utilizaron el concepto de un identificador reubicable , una referencia a la memoria que permitía mover los datos reales a los que se hacía referencia sin invalidar el identificador. El esquema de Apple era simple: un identificador era simplemente un puntero a una tabla (no reubicable) de punteros adicionales, que a su vez apuntaban a los datos. [2] Si una solicitud de memoria requería compactación de memoria, esto se hacía y la tabla, llamada bloque de puntero maestro, se actualizaba. La máquina en sí implementó dos áreas en la memoria disponibles para este esquema: el montón del sistema (usado para el sistema operativo) y el montón de la aplicación. [3] Siempre que solo se ejecutara una aplicación a la vez, el sistema funcionaba bien. Dado que todo el montón de la aplicación se disolvía cuando la aplicación salía, se minimizaba la fragmentación.

El sistema de gestión de memoria tenía debilidades; el montón del sistema no estaba protegido de aplicaciones erráticas, como hubiera sido posible si la arquitectura del sistema hubiera admitido la protección de memoria , y esto era con frecuencia la causa de problemas y fallas del sistema. [4] Además, el enfoque basado en identificadores también abrió una fuente de errores de programación, donde no se podía garantizar que los punteros a datos dentro de dichos bloques reubicables siguieran siendo válidos en las llamadas que pudieran hacer que la memoria se moviera. Este era un problema real para casi todas las API de sistema que existían. Debido a la transparencia de las estructuras de datos propiedad del sistema en ese momento, las API podían hacer poco para resolver esto. Por lo tanto, la responsabilidad recaía en el programador de no crear dichos punteros, o al menos administrarlos con mucho cuidado desreferenciando todos los identificadores después de cada llamada de API de ese tipo. Dado que muchos programadores no estaban familiarizados en general con este enfoque, los primeros programas Mac sufrieron con frecuencia fallas que surgían de esto. [5]

Palm OS y Windows de 16 bits utilizan un esquema similar para la gestión de memoria, pero las versiones de Palm y Windows hacen que los errores de programación sean más difíciles. Por ejemplo, en Mac OS, para convertir un identificador en un puntero, un programa simplemente desreferencia el identificador directamente, pero si el identificador no está bloqueado, el puntero puede volverse inválido rápidamente. Las llamadas a bloquear y desbloquear identificadores no están equilibradas; diez llamadas a HLockse deshacen con una sola llamada a HUnlock. [6] En Palm OS y Windows, los identificadores son un tipo opaco y se deben desreferenciar con MemHandleLocken Palm OS o Global/LocalLocken Windows. Cuando una aplicación de Palm o Windows finaliza con un identificador, llama a MemHandleUnlocko Global/LocalUnlock. Palm OS y Windows mantienen un recuento de bloqueos para los bloques; después de tres llamadas a MemHandleLock, un bloque solo se desbloqueará después de tres llamadas a MemHandleUnlock.

Abordar el problema de los bloqueos y desbloqueos anidados puede ser sencillo (aunque tedioso) mediante el empleo de varios métodos, pero estos interfieren en la legibilidad del bloque de código asociado y requieren conciencia y disciplina por parte del codificador.

Fugas de memoria y referencias obsoletas

También son necesarias la conciencia y la disciplina para evitar "fugas" de memoria (fallas en la desasignación dentro del alcance de la asignación) y para evitar referencias a controladores obsoletos después de la liberación (lo que generalmente resultaba en un bloqueo grave , molesto en un sistema de tarea única, potencialmente desastroso si se están ejecutando otros programas).

Conmutador

La situación empeoró con la llegada de Switcher , que era una forma de que un Mac con 512 KB o más de memoria pudiera ejecutar múltiples aplicaciones a la vez. [7] Este fue un paso necesario para los usuarios, que encontraban muy limitante el enfoque de una aplicación a la vez. Debido a que Apple ahora estaba comprometido con su modelo de administración de memoria, así como con la compatibilidad con las aplicaciones existentes, se vio obligado a adoptar un esquema en el que a cada aplicación se le asignaba su propio montón de la RAM disponible. La cantidad de RAM real asignada a cada montón se establecía mediante un valor codificado en los metadatos de cada aplicación, establecido por el programador. A veces, este valor no era suficiente para determinados tipos de trabajo, por lo que la configuración del valor tenía que exponerse al usuario para permitirle ajustar el tamaño del montón para adaptarlo a sus propios requisitos. Si bien era popular entre los " usuarios avanzados ", esta exposición de un detalle de implementación técnica iba en contra de la filosofía del usuario de Mac. Además de exponer a los usuarios a tecnicismos esotéricos, era ineficiente, ya que se obligaba a una aplicación a utilizar toda la memoria RAM asignada, aunque luego dejara la mayor parte sin utilizar. Otra aplicación podría quedarse sin memoria, pero no podría utilizar la memoria libre "propiedad" de otra aplicación. [3]

Si bien una aplicación no podría utilizar de forma beneficiosa el montón de otra aplicación, ciertamente podría destruirlo, generalmente al escribir inadvertidamente en una dirección sin sentido. Una aplicación que tratara accidentalmente un fragmento de texto o imagen, o una ubicación no asignada como puntero, podría sobrescribir fácilmente el código o los datos de otras aplicaciones o incluso del sistema operativo, dejando "lurkers" incluso después de salir del programa. Estos problemas podrían ser extremadamente difíciles de analizar y corregir.

Switcher evolucionó a MultiFinder en System 4.2, que se convirtió en el Administrador de procesos en System 7 , y para entonces el esquema ya estaba arraigado desde hacía mucho tiempo. Apple hizo algunos intentos de evitar las limitaciones obvias (la memoria temporal era una de ellas, donde una aplicación podía "tomar prestada" RAM libre que se encontraba fuera de su montón por períodos cortos), pero esto no era popular entre los programadores, por lo que en gran medida no logró resolver los problemas. El complemento System 7 Tune-up de Apple agregó un tamaño de memoria "mínimo" y un tamaño "preferido" (si la cantidad de memoria preferida no estaba disponible, el programa podía iniciarse en el espacio mínimo, posiblemente con una funcionalidad reducida). Esto se incorporó al sistema operativo estándar a partir de System 7.1, pero aún no solucionó el problema de raíz. [8]

Los esquemas de memoria virtual , que permitían disponer de más memoria paginando las porciones no utilizadas de memoria en el disco, fueron puestos a disposición por utilidades de terceros como Connectix Virtual y luego por Apple en System 7. Esto aumentó la capacidad de memoria de Macintosh a costa del rendimiento, pero no agregó memoria protegida ni evitó la compactación del montón del administrador de memoria que invalidaría algunos punteros.

32 bits limpio

Originalmente, el Macintosh tenía 128 KB de RAM, con un límite real de 4 MB, a pesar de estar soldado. Este límite se alcanzó por primera vez con el Macintosh Plus y su memoria actualizable por el usuario. Estas primeras computadoras Macintosh usan la CPU 68000 , un procesador de 32 bits, que tiene solo 24 líneas de dirección física. Las 24 líneas permiten al procesador direccionar hasta 16 MB de memoria (224 bytes ), lo que se consideró una cantidad suficiente en ese momento. El límite de RAM en el diseño de Macintosh era de 4 MB de RAM y 4 MB de ROM con las direcciones restantes de 8 MB divididas entre los chips SCC, IWM y VIA , debido a la estructura del mapa de memoria. [9] [10] Esto se solucionó cambiando el mapa de memoria con el Macintosh II , permitiendo hasta 8 MB de RAM, reduciendo las direcciones de ROM y E/S a 1 MB cada una y asignando las direcciones restantes de 6 MB a las ranuras NuBus . Los productos Connectix MAXIMA, RAM Doubler y Virtual permitieron acceder y reasignar las direcciones de 6 MB asignadas a las tarjetas NuBus para un total de 14 MB, menos 1 MB por ranura ocupada. [11] [12]

Como la memoria era un recurso escaso, los autores del Mac OS clásico decidieron aprovechar el byte no utilizado en cada dirección. El administrador de memoria original (hasta la llegada del Sistema 7) colocaba indicadores en los 8 bits superiores de cada puntero y manejador de 32 bits . Cada dirección contenía indicadores como "bloqueado", "purgable" o "recurso", que se almacenaban en la tabla de punteros maestros. Cuando se usaban como una dirección real, estos indicadores se ocultaban y la CPU los ignoraba. [4]

Si bien era un buen uso de un espacio de RAM muy limitado, este diseño causó problemas cuando Apple presentó el Macintosh II, que utilizaba la CPU Motorola 68020 de 32 bits . La 68020 tenía 32 líneas de dirección física que podían direccionar hasta 4 GB de memoria. Los indicadores que el Administrador de memoria almacenaba en el byte alto de cada puntero y controlador eran importantes ahora y podían provocar errores de direccionamiento.

En las máquinas Macintosh IIci y posteriores, HLock()se reescribieron otras API para implementar el bloqueo de identificadores de una manera distinta a la de marcar los bits altos de los identificadores. Pero muchos programadores de aplicaciones Macintosh y gran parte del código del software del sistema Macintosh accedían a los indicadores directamente en lugar de usar las API, como HLock(), que se habían proporcionado para manipularlos. Al hacer esto, hicieron que sus aplicaciones fueran incompatibles con el direccionamiento de 32 bits verdadero, y esto se conoció como no estar "limpio en 32 bits".

Para detener los bloqueos continuos del sistema causados ​​por este problema, System 6 y versiones anteriores que se ejecutaban en un 68020 o un 68030 obligaban a la máquina a entrar en modo de 24 bits y solo reconocían y direccionaban los primeros 8 megabytes de RAM, un defecto obvio en máquinas cuyo hardware estaba cableado para aceptar hasta 128 MB de RAM y cuya documentación de producto anunciaba esta capacidad. Con System 7, el software del sistema Mac finalmente se hizo limpio en 32 bits, pero aún existía el problema de las ROM sucias. El problema era que la decisión de utilizar direccionamiento de 24 bits o 32 bits tenía que tomarse muy temprano en el proceso de arranque, cuando las rutinas de ROM inicializaban el Administrador de memoria para configurar un entorno Mac básico donde se cargaban y ejecutaban las ROM NuBus y los controladores de disco. Las ROM más antiguas no tenían soporte para el Administrador de memoria de 32 bits y, por lo tanto, no era posible arrancar en modo de 32 bits. Sorprendentemente, la primera solución a este fallo fue publicada por la empresa de utilidades de software Connectix , cuya extensión para System 6, OPTIMA, reinicializó el Administrador de memoria y repitió partes tempranas del proceso de arranque de Mac, permitiendo que el sistema arranque en modo de 32 bits y habilitando el uso de toda la RAM en la máquina. OPTIMA luego evolucionaría al producto más conocido de 1991, MODE32 , para System 7. Apple licenció el software de Connectix más tarde en 1991 y lo distribuyó de forma gratuita. Las computadoras Macintosh IIci y más tarde las Macintosh basadas en Motorola tenían ROM limpias de 32 bits.

Pasó bastante tiempo hasta que las aplicaciones se actualizaron para eliminar todas las dependencias de 24 bits, y System 7 proporcionó una forma de volver al modo de 24 bits si se encontraban incompatibilidades en las aplicaciones. [3] En el momento de la migración a PowerPC y System 7.1.2, la limpieza de 32 bits era obligatoria para crear aplicaciones nativas e incluso más tarde, las Mac basadas en Motorola 68040 no podían soportar el modo de 24 bits. [6] [13]

Orientación a objetos

El auge de los lenguajes orientados a objetos para la programación de Mac (primero Object Pascal y luego C++ ) también causó problemas para el modelo de memoria adoptado. Al principio, parecía natural que los objetos se implementaran mediante identificadores, para obtener la ventaja de ser reubicables. Estos lenguajes, tal como fueron diseñados originalmente, utilizaban punteros para los objetos, lo que daría lugar a problemas de fragmentación. Una solución, implementada por los compiladores THINK (posteriormente Symantec ) , fue utilizar identificadores internamente para los objetos, pero utilizar una sintaxis de puntero para acceder a ellos. Esto parecía una buena idea al principio, pero pronto surgieron problemas profundos, ya que los programadores no podían saber si estaban tratando con un bloque reubicable o fijo, y por lo tanto no tenían forma de saber si debían asumir la tarea de bloquear objetos o no. Huelga decir que esto dio lugar a una gran cantidad de errores y problemas con estas primeras implementaciones de objetos. Los compiladores posteriores no intentaron hacer esto, sino que utilizaron punteros reales, a menudo implementando sus propios esquemas de asignación de memoria para solucionar el modelo de memoria de Mac OS.

Aunque el modelo de memoria de Mac OS, con todos sus problemas inherentes, se mantuvo así hasta Mac OS 9 , debido a las severas restricciones de compatibilidad de aplicaciones, la creciente disponibilidad de RAM barata significó que, en general, la mayoría de los usuarios podían actualizar su sistema para salir de un apuro. La memoria no se usaba de manera eficiente, pero era lo suficientemente abundante como para que el problema nunca se volviera crítico. Esto es irónico dado que el propósito del diseño original era maximizar el uso de cantidades muy limitadas de memoria. Mac OS X finalmente eliminó todo el esquema, implementando un esquema de memoria virtual paginada moderno . Un subconjunto de las API del modelo de memoria más antiguo aún existe para compatibilidad como parte de Carbon , pero se asigna al administrador de memoria moderno (una implementación segura para subprocesos malloc) subyacente. [6] Apple recomienda que el código de Mac OS X use mallocy free"casi exclusivamente". [14]

Referencias

  1. ^ Hertzfeld, Andy (septiembre de 1983), The Original Macintosh: We're Not Hackers!, consultado el 10 de mayo de 2010
  2. ^ Hertzfeld, Andy (enero de 1982), The Original Macintosh: Hungarian, archivado desde el original el 19 de junio de 2010 , consultado el 10 de mayo de 2010
  3. ^ abc memorymanagement.org (15 de diciembre de 2000), Gestión de memoria en Mac OS, archivado desde el original el 16 de mayo de 2010 , consultado el 10 de mayo de 2010
  4. ^ ab Hertzfeld, Andy , The Original Macintosh: Mea Culpa , consultado el 10 de mayo de 2010
  5. ^ Apple Computer (1 de octubre de 1985), Nota técnica OV09: Depuración con PurgeMem y CompactMem , consultado el 10 de mayo de 2010
  6. ^ Referencia del administrador de memoria heredada de abc , Apple Inc. , 27 de junio de 2007 , consultado el 10 de mayo de 2010
  7. ^ Hertzfeld, Andy (octubre de 1984), The Original Macintosh: Switcher , consultado el 10 de mayo de 2010
  8. ^ "Guía de actualización del sistema 7.1" (PDF) . Archivado desde el original (PDF) el 4 de marzo de 2016. Consultado el 26 de mayo de 2015 .
  9. ^ Transición del direccionamiento de 24 bits al de 32 bits - GUI de Mac
  10. ^ "mapas de memoria". Osdata.com. 28 de marzo de 2001. Consultado el 11 de mayo de 2010 .
  11. ^ Archivo Daystar, Preguntas frecuentes sobre Mode32 - LowEndMac
  12. ^ MODE32 Versión 7.5: Notas de lanzamiento e instrucciones importantes
  13. ^ Apple Computer (1 de enero de 1991), Nota técnica ME13: compatibilidad del administrador de memoria , consultado el 10 de mayo de 2010
  14. ^ Recomendaciones de asignación de memoria en OS X, Apple Inc , 12 de julio de 2005 , consultado el 22 de septiembre de 2009

Enlaces externos