Articulo de referencia

Gestión de memoria clásica de Mac OS

Ventana "Acerca de este ordenador" de Mac OS 9.1 que muestra el consumo de memoria de cada aplicación abierta y del propio software del sistema. Históricamente, el Mac OS clásic...

Ventana "Acerca de este ordenador" de Mac OS 9.1 que muestra el consumo de memoria de cada aplicación abierta y del propio software del sistema.

Históricamente, el Mac OS clásico utilizaba un sistema de gestión de memoria que ha caído en desuso en los sistemas modernos. La crítica a este enfoque fue uno de los aspectos clave que se abordaron en el cambio a Mac OS X.

El problema original para los ingenieros del Macintosh fue cómo aprovechar al máximo los 128  KB de RAM con los que estaba equipado el equipo, en un hardware basado en el Motorola 68000 que no admitía memoria virtual . [ 1 ] Dado que en aquel entonces el equipo solo podía ejecutar un programa a la vez y no disponía de almacenamiento secundario fijo , los ingenieros implementaron un esquema sencillo que funcionaba bien con esas limitaciones. Esta elección de diseño no se adaptó bien al desarrollo del equipo, lo que generó diversas dificultades tanto para programadores como para usuarios.

Fragmentación

La principal preocupación de los ingenieros originales parece haber sido la fragmentación , es decir, la asignación y liberación repetida de memoria a través de punteros, lo que genera muchas áreas pequeñas y aisladas de memoria que no se pueden usar porque son demasiado pequeñas, incluso cuando la memoria libre total puede ser suficiente para satisfacer una solicitud de memoria particular. Para resolver esto, los ingenieros de Apple utilizaron el concepto de identificador reubicable , una referencia a la memoria que permitía mover los datos 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, esta se realizaba y la tabla, llamada bloque de punteros maestro, se actualizaba. La propia máquina implementó dos áreas de memoria disponibles para este esquema: el montón del sistema (utilizado para el sistema operativo) y el montón de la aplicación. [ 3 ] Mientras 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 finalizaba, la fragmentación se minimizaba.

El sistema de gestión de memoria tenía debilidades; el montón del sistema no estaba protegido de aplicaciones erróneas, como habría sido posible si la arquitectura del sistema hubiera admitido la protección de memoria , y esto frecuentemente causaba problemas y fallos 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 permanecieran válidos entre llamadas que pudieran causar el movimiento de memoria. Esto era un problema real para casi todas las API del sistema existentes. Debido a la transparencia de las estructuras de datos propiedad del sistema en ese momento, las API poco podían hacer para resolver esto. Por lo tanto, la responsabilidad recaía en el programador para no crear tales punteros, o al menos gestionarlos con mucho cuidado desreferenciando todos los identificadores después de cada llamada a la API. Dado que muchos programadores generalmente no estaban familiarizados con este enfoque, los primeros programas de Mac sufrían frecuentemente de fallos derivados 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 el error del programador sea más difícil. 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 para 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 deben desreferenciarse con MemHandleLocken Palm OS o Global/LocalLocken Windows. Cuando una aplicación de Palm o Windows termina con un identificador, llama a MemHandleUnlocko Global/LocalUnlock. Palm OS y Windows mantienen un contador 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 uso de diversos métodos, pero estos dificultan la legibilidad del bloque de código asociado y requieren atención y disciplina por parte del programador.

Fugas de memoria y referencias obsoletas

También es necesario tener conciencia y disciplina para evitar "fugas" de memoria (fallo al liberar la memoria dentro del ámbito de la asignación) y para evitar referencias a identificadores obsoletos después de su liberación (lo que generalmente resultaba en un fallo grave , molesto en un sistema de una sola tarea y potencialmente desastroso si se están ejecutando otros programas).

Conmutador

La situación empeoró con la llegada de Switcher , que permitía a los Mac con 512  KB o más de memoria ejecutar varias aplicaciones simultáneamente. [ 7 ] Este fue un avance necesario para los usuarios, que consideraban muy limitante el enfoque de una aplicación a la vez. Dado que Apple estaba ahora comprometida con su modelo de gestión de memoria, así como con la compatibilidad con las aplicaciones existentes, se vio obligada a adoptar un esquema en el que a cada aplicación se le asignaba su propio montón de la RAM disponible. La cantidad real de RAM asignada a cada montón se establecía mediante un valor codificado en los metadatos de cada aplicación, definido por el programador. A veces, este valor no era suficiente para ciertos tipos de trabajo, por lo que la configuración del valor debía estar disponible para el usuario, permitiéndole ajustar el tamaño del montón según sus necesidades. Si bien era popular entre los "usuarios avanzados " , esta exposición de un detalle técnico de la implementación 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 una aplicación se veía obligada a acaparar toda la RAM asignada, incluso si posteriormente dejaba la mayor parte sin usar. Otra aplicación podía quedarse sin memoria, pero no podía utilizar la memoria libre "propiedad" de otra aplicación. [ 3 ]

Si bien una aplicación no puede aprovechar la memoria dinámica de otra, sí puede destruirla, generalmente al escribir accidentalmente en una dirección sin sentido. Una aplicación que trate por error un fragmento de texto o imagen, o una ubicación no asignada, como un puntero, podría sobrescribir fácilmente el código o los datos de otras aplicaciones o incluso del sistema operativo, dejando rastros persistentes incluso después de que el programa haya finalizado. Estos problemas pueden ser extremadamente difíciles de analizar y corregir.

Switcher evolucionó a MultiFinder en System 4.2, que se convirtió en Process Manager en System 7 , y para entonces el esquema ya estaba muy arraigado. Apple intentó sortear las limitaciones obvias; una de ellas era la memoria temporal, que permitía a una aplicación "tomar prestada" RAM libre que se encontraba fuera de su montón durante cortos periodos, pero esto no era popular entre los programadores, por lo que en gran medida no resolvió los problemas. El complemento System 7 Tune-up de Apple añadió 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 ejecutarse 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 así no abordó el problema de raíz. [ 8 ]

Los esquemas de memoria virtual , que liberaban memoria al paginar las porciones no utilizadas de la memoria en el disco, fueron implementados por utilidades de terceros como Connectix Virtual y, posteriormente, por Apple en System 7. Esto aumentó la capacidad de memoria de Macintosh a costa del rendimiento, pero no añadió memoria protegida ni evitó la compactación del montón del administrador de memoria, que invalidaba algunos punteros.

limpieza de 32 bits

Originalmente, el Macintosh tenía 128  KB de RAM, con un límite real de 4  MB, a pesar de estar soldada. Este límite se alcanzó por primera vez con el Macintosh Plus y su memoria actualizable por el usuario. Estos primeros ordenadores Macintosh utilizan la CPU 68000 , un procesador de 32 bits que tiene solo 24 líneas de dirección físicas. Las 24 líneas de dirección permiten al procesador direccionar hasta 16  MB de memoria ( 2²⁴ bytes), lo que se consideraba suficiente en ese momento. La estructura del mapa de memoria dividía este espacio de direcciones en máximos de 4  MB de RAM, 4  MB de ROM y los 8  MB restantes de direcciones repartidos entre los chips SCC, IWM y VIA . [ 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 de 6 MB restantes  a las ranuras NuBus . Los productos MAXIMA, RAM Doubler y Virtual de Connectix  permitieron acceder y reasignar las direcciones de 6 MB para las tarjetas NuBus para un total de 14  MB, menos 1  MB por ranura ocupada. [ 11 ] [ 12 ]

Debido a que la memoria era un recurso escaso, los autores de Classic Mac OS decidieron aprovechar el byte no utilizado en cada dirección. El Administrador de Memoria original (hasta la llegada de System 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 maestra de punteros. Cuando se utilizaba como una dirección real, estos indicadores se enmascaraban y la CPU los ignoraba. [ 4 ]

Si bien este diseño permitía un buen uso del limitado espacio de RAM, causó problemas cuando Apple lanzó el Macintosh II, que utilizaba la CPU Motorola 68020 de 32 bits . El 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 manejador adquirieron gran importancia y podían provocar errores de direccionamiento.

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

Para evitar los continuos fallos del sistema causados ​​por este problema, System 6 y versiones anteriores, al ejecutarse en un procesador 68020 o 68030, forzaban al equipo al modo de 24 bits y solo reconocían y direccionaban los primeros 8 megabytes de RAM. Esto representaba un fallo evidente en equipos cuyo hardware estaba configurado para admitir hasta 128  MB de RAM, y cuya documentación de producto anunciaba esta capacidad. Con System 7, el software del sistema Mac finalmente se optimizó para 32 bits, pero persistía el problema de las ROMs defectuosas. El problema radicaba en que la decisión de usar direccionamiento de 24 o 32 bits debía tomarse muy pronto en el proceso de arranque, cuando las rutinas de la ROM inicializaban el Administrador de Memoria para configurar un entorno Mac básico donde se cargaban y ejecutaban las ROMs NuBus y los controladores de disco. Las ROMs antiguas no tenían soporte para el Administrador de Memoria de 32 bits, por lo que 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, reinicializaba el Administrador de Memoria y repetía las primeras partes del proceso de arranque de Mac, permitiendo que el sistema arrancara en modo de 32 bits y habilitando el uso de toda la RAM de la máquina. OPTIMA evolucionaría más tarde hasta convertirse en el producto más conocido de 1991, MODE32 , para System 7. Apple obtuvo la licencia del software de Connectix a finales de 1991 y lo distribuyó gratuitamente. Los ordenadores Macintosh IIci y posteriores Macintosh basados ​​en Motorola tenían ROMs limpias de 32 bits.

Pasó bastante tiempo antes de que las aplicaciones se actualizaran 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 de aplicaciones. [ 3 ] Para cuando se migró a PowerPC y System 7.1.2, la compatibilidad con 32 bits era obligatoria para crear aplicaciones nativas, e incluso los Mac posteriores basados ​​en Motorola 68040 no podían admitir el modo de 24 bits. [ 6 ] [ 13 ]

Orientación del objeto

El auge de los lenguajes orientados a objetos para programar en Mac —primero Object Pascal , y luego C++ — también generó problemas con el modelo de memoria adoptado. Al principio, parecía lógico que los objetos se implementaran mediante identificadores (handles), para aprovechar la ventaja de la reubicación. Estos lenguajes, en su diseño original, utilizaban punteros para los objetos, lo que provocaba problemas de fragmentación. Una solución, implementada por los compiladores THINK (posteriormente Symantec ) , consistió en usar identificadores internamente para los objetos, pero acceder a ellos mediante una sintaxis de puntero. Esto parecía una buena idea al principio, pero pronto surgieron graves problemas, ya que los programadores no podían distinguir entre un bloque reubicable y uno fijo, y por lo tanto, no tenían forma de saber si debían bloquear los objetos o no. Como era de esperar, esto provocó 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, implementando a menudo sus propios esquemas de asignación de memoria para sortear 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 las aplicaciones, la creciente disponibilidad de RAM barata significó que, en general, la mayoría de los usuarios podían solucionar el problema actualizando sus sistemas. La memoria no se utilizaba de forma 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 moderno de memoria virtual paginada . Un subconjunto de las API del modelo de memoria anterior todavía existe para la 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 utilice mallocy free"casi exclusivamente". [ 14 ]

Referencias

  1. Hertzfeld, Andy (septiembre de 1983), El Macintosh original: ¡No somos hackers!, consultado el 10 de mayo de 2010.
  2. Hertzfeld, Andy (enero de 1982), The Original Macintosh: Hungarian , archivado del original el 19 de junio de 2010 , recuperado el 10 de mayo de 2010.
  3. 1 2 3 memorymanagement.org (15 de diciembre de 2000), Gestión de memoria en Mac OS , archivado del original el 16 de mayo de 2010 , recuperado el 10 de mayo de 2010
  4. 1 2 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. 1 2 3 Referencia del administrador de memoria heredado , 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 del original (PDF) el 4 de marzo de 2016. Consultado el 26 de mayo de 2015 .
  9. Transición de direccionamiento de 24 bits a 32 bits - Interfaz gráfica de usuario 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 e instrucciones importantes de la versión
  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 .
  • Macintosh: Tamaño de la ROM para varios modelos , Apple Inc. , 23 de agosto de 2000, archivado del original el 15 de octubre de 2009 , consultado el 22 de septiembre de 2009.