Klassische Mac OS-Speicherverwaltung - Classic Mac OS memory management

"Über diesen Computer" Mac OS 9.1- Fenster zeigt den Speicherverbrauch jeder geöffneten Anwendung und der Systemsoftware selbst an.

In der Vergangenheit verwendete das klassische Mac OS eine Form der Speicherverwaltung , die in modernen Systemen in Ungnade gefallen ist. Die Kritik an diesem Ansatz war einer der Schlüsselbereiche, auf die sich die Umstellung auf Mac OS X bezog .

Das ursprüngliche Problem für die Ingenieure des Macintosh bestand darin, die 128 KB RAM, mit denen der Computer ausgestattet war, auf Motorola 68000- basierter Computerhardware, die keinen virtuellen Speicher unterstützte , optimal zu nutzen . Da zu diesem Zeitpunkt auf der Maschine jeweils nur ein Anwendungsprogramm ausgeführt werden konnte und kein fester Sekundärspeicher vorhanden war , implementierten die Ingenieure ein einfaches Schema, das mit diesen besonderen Einschränkungen gut funktionierte. Diese Wahl des Designs ließ sich mit der Entwicklung der Maschine nicht gut skalieren, was sowohl für Programmierer als auch für Benutzer verschiedene Schwierigkeiten verursachte.

Zersplitterung

Das Hauptanliegen der ursprünglichen Ingenieure scheint die Fragmentierung gewesen zu sein - das heißt, die wiederholte Zuweisung und Freigabe des Speichers durch Zeiger, die zu vielen kleinen isolierten Speicherbereichen führen, die nicht verwendet werden können, weil sie zu klein sind, obwohl der gesamte freie Speicher dies kann ausreichend sein, um eine bestimmte Speicheranforderung zu erfüllen. Um dies zu lösen, von Apple das Konzept eines verlegbaren Ingenieure Handgriff , ein Verweis auf Speicher, der die eigentlichen Daten erlaubt bezeichnet werden bewegt , ohne den Griff ungültig zu machen. Apples Schema war einfach - ein Handle war einfach ein Zeiger auf eine (nicht verschiebbare) Tabelle weiterer Zeiger, die wiederum auf die Daten zeigte. Wenn für eine Speicheranforderung eine Komprimierung des Speichers erforderlich war, wurde dies durchgeführt und die Tabelle, die als Hauptzeigerblock bezeichnet wird, wurde aktualisiert. Die Maschine selbst hat zwei für dieses Schema verfügbare Speicherbereiche implementiert - den Systemheap (für das Betriebssystem verwendet) und den Anwendungsheap. Solange jeweils nur eine Anwendung ausgeführt wurde, funktionierte das System einwandfrei. Da der gesamte Anwendungsheap beim Beenden der Anwendung aufgelöst wurde, wurde die Fragmentierung minimiert.

Das Speicherverwaltungssystem hatte Schwächen; Der Systemheap war nicht vor fehlerhaften Anwendungen geschützt, wie dies möglich gewesen wäre, wenn die Systemarchitektur den Speicherschutz unterstützt hätte , und dies war häufig die Ursache für Systemprobleme und Abstürze. Darüber hinaus eröffnete der Handle-basierte Ansatz auch eine Quelle für Programmierfehler, bei denen nicht garantiert werden konnte, dass Zeiger auf Daten in solchen verschiebbaren Blöcken bei Aufrufen gültig bleiben, die dazu führen könnten, dass sich der Speicher verschiebt. Dies war ein echtes Problem für fast jede existierende System- API . Aufgrund der Transparenz der systemeigenen Datenstrukturen zu dieser Zeit konnten die APIs wenig dazu beitragen, dies zu lösen. Daher war es die Aufgabe des Programmierers, solche Zeiger nicht zu erstellen oder zumindest sehr sorgfältig zu verwalten, indem alle Handles nach jedem solchen API-Aufruf dereferenziert wurden. Da viele Programmierer mit diesem Ansatz im Allgemeinen nicht vertraut waren, litten frühe Mac-Programme häufig unter Fehlern, die sich daraus ergaben.

Palm OS und 16-Bit-Windows verwenden ein ähnliches Schema für die Speicherverwaltung, aber die Versionen Palm und Windows erschweren Programmiererfehler. Wenn Sie beispielsweise unter Mac OS ein Handle in einen Zeiger konvertieren, referenziert ein Programm das Handle nur direkt. Wenn das Handle jedoch nicht gesperrt ist, kann der Zeiger schnell ungültig werden. Anrufe zum Sperren und Entsperren von Griffen sind nicht ausgeglichen. Zehn Anrufe an HLock werden durch einen einzigen Anruf an rückgängig gemacht HUnlock . In Palm OS und Windows sind Handles ein undurchsichtiger Typ und müssen unter MemHandleLock Palm OS oder Global/LocalLock Windows nicht mehr referenziert werden . Wenn eine Palm- oder Windows-Anwendung mit einem Handle fertig ist, ruft sie MemHandleUnlock oder auf Global/LocalUnlock . Palm OS und Windows behalten die Anzahl der Sperren für Blöcke bei. Nach drei Aufrufen von MemHandleLock wird ein Block erst nach drei Aufrufen von entsperrt MemHandleUnlock .

Das Problem verschachtelter Sperren und Entsperrungen kann mithilfe verschiedener Methoden unkompliziert (wenn auch mühsam) angegangen werden. Diese beeinträchtigen jedoch die Lesbarkeit des zugehörigen Codeblocks und erfordern Kenntnis und Disziplin seitens des Codierers.

Speicherlecks und veraltete Referenzen

Bewusstsein und Disziplin sind auch erforderlich, um Speicherlecks zu vermeiden (Fehler bei der Freigabe im Rahmen der Zuweisung) und Verweise auf veraltete Handles nach der Freigabe zu vermeiden (was normalerweise zu einem schweren Absturz führte - möglicherweise störend für ein Single-Tasking-System katastrophal, wenn andere Programme ausgeführt werden).

Switcher

Die Situation verschlechterte sich mit dem Aufkommen von Switcher , mit dem ein Mac mit 512 KB oder mehr Speicher mehrere Anwendungen gleichzeitig ausführen konnte. Dies war ein notwendiger Schritt vorwärts für Benutzer, die den Ansatz einer einzelnen App als sehr einschränkend empfanden. Da Apple nun seinem Speicherverwaltungsmodell sowie der Kompatibilität mit vorhandenen Anwendungen verpflichtet war, musste es ein Schema anwenden, bei dem jeder Anwendung aus dem verfügbaren RAM ein eigener Heap zugewiesen wurde. Die Menge an tatsächlichem RAM, die jedem Heap zugewiesen wurde, wurde durch einen Wert festgelegt, der in den Metadaten jeder Anwendung codiert ist und vom Programmierer festgelegt wurde. Manchmal reichte dieser Wert für bestimmte Arten von Arbeiten nicht aus, sodass die Werteinstellung dem Benutzer zur Verfügung gestellt werden musste, damit er die Größe des Heapspeichers an seine eigenen Anforderungen anpassen konnte. Diese Enthüllung eines technischen Implementierungsdetails war zwar bei " Power-Usern " beliebt , widersprach jedoch der Mac-Benutzerphilosophie. Abgesehen davon, dass Benutzer esoterischen technischen Problemen ausgesetzt waren, war es ineffizient, da eine Anwendung erstellt werden sollte, um den gesamten zugewiesenen RAM zu nutzen, selbst wenn das meiste davon später nicht verwendet wurde. Eine andere Anwendung verfügt möglicherweise nicht über genügend Speicher, kann jedoch den freien Speicher einer anderen Anwendung nicht nutzen.

Während eine Anwendung den Heap einer Schwesteranwendung nicht vorteilhaft nutzen konnte, konnte sie ihn sicherlich zerstören, normalerweise durch versehentliches Schreiben an eine unsinnige Adresse. Eine Anwendung, die versehentlich ein Text- oder Bildfragment oder einen nicht zugewiesenen Ort als Zeiger behandelt, kann den Code oder die Daten anderer Anwendungen oder sogar des Betriebssystems leicht überschreiben und selbst nach dem Beenden des Programms "Lauerer" hinterlassen. Solche Probleme können äußerst schwierig zu analysieren und zu beheben sein.

Switcher entwickelte sich in System 4.2 zu MultiFinder , der in System 7 zum Prozessmanager wurde , und bis dahin war das Schema lange verwurzelt. Apple unternahm einige Versuche, um die offensichtlichen Einschränkungen zu umgehen - temporärer Speicher war einer, bei dem eine Anwendung freien RAM "ausleihen" konnte, der für kurze Zeit außerhalb ihres Heaps lag. Dies war jedoch bei Programmierern unpopulär, sodass die Probleme größtenteils nicht gelöst werden konnten. Das System 7 Tune-up-Addon von Apple fügte eine "minimale" Speichergröße und eine "bevorzugte" Größe hinzu. Wenn die bevorzugte Speichermenge nicht verfügbar war, konnte das Programm auf kleinstem Raum gestartet werden, möglicherweise mit reduzierter Funktionalität. Dies wurde ab System 7.1 in das Standardbetriebssystem integriert, das Root-Problem wurde jedoch immer noch nicht behoben.

Virtuelle Speicherschemata , die mehr Speicher verfügbar machten, indem nicht verwendete Teile des Speichers auf die Festplatte übertragen wurden, wurden von Dienstprogrammen von Drittanbietern wie Connectix Virtual und anschließend von Apple in System 7 bereitgestellt . Dies erhöhte die Speicherkapazität des Macintosh zu Leistungskosten, fügte jedoch keinen geschützten Speicher hinzu oder verhinderte nicht die Heap-Komprimierung des Speichermanagers, die einige Zeiger ungültig machen würde.

32-Bit sauber

Ursprünglich hatte der Macintosh 128 KB RAM mit einer Grenze von 512 KB. Dies wurde mit der Einführung des Macintosh Plus auf 4 MB erhöht . Diese Macintosh-Computer verwendeten die 68000- CPU, einen 32-Bit-Prozessor, hatten jedoch nur 24 physische Adressleitungen. Die 24 Zeilen ermöglichten es dem Prozessor, bis zu 16 MB Speicher (2 bis 24 Byte) zu adressieren , was zu diesem Zeitpunkt als ausreichende Menge angesehen wurde. Die RAM-Grenze im Macintosh-Design betrug aufgrund der Struktur der Speicherzuordnung 4 MB RAM und 4 MB ROM . Dies wurde behoben, indem die Speicherzuordnung mit dem Macintosh II und dem Macintosh Portable geändert wurde und bis zu 8 MB RAM zugelassen wurden.

Da Speicher eine knappe Ressource war, beschlossen die Autoren von Mac OS, das nicht verwendete Byte in jeder Adresse zu nutzen. Der ursprüngliche Speichermanager (bis zum Aufkommen von System 7) platzierte Flags in den hohen 8 Bits jedes 32-Bit- Zeigers und Handles . Jede Adresse enthielt Flags wie "gesperrt", "löschbar" oder "Ressource", die in der Hauptzeigertabelle gespeichert wurden. Bei Verwendung als tatsächliche Adresse wurden diese Flags von der CPU ausgeblendet und ignoriert.

Dieses Design nutzte zwar nur sehr wenig RAM-Speicher, verursachte jedoch Probleme, als Apple den Macintosh II einführte, der die 32-Bit- Motorola 68020- CPU verwendete. Der 68020 verfügte über 32 physische Adressleitungen, die bis zu 4 GB (2 32 Byte) Speicher adressieren konnten. Die Flags, die der Speichermanager im High-Byte jedes Zeigers und Handles gespeichert hat, waren jetzt signifikant und können zu Adressierungsfehlern führen.

Theoretisch war es den Architekten der Macintosh-Systemsoftware freigestellt, das Schema "Flags im High-Byte" zu ändern, um dieses Problem zu vermeiden, und das taten sie auch. Auf dem Macintosh IIci und späteren Computern wurden beispielsweise HLock() andere APIs neu geschrieben, um das Sperren von Handles auf eine andere Weise zu implementieren, als die hohen Bits von Handles zu kennzeichnen. Viele Macintosh-Anwendungsprogrammierer und ein Großteil des Macintosh-Systemsoftwarecodes selbst haben jedoch direkt auf die Flags zugegriffen, anstatt die APIs zu verwenden, HLock() die zur Manipulation bereitgestellt wurden. Auf diese Weise machten sie ihre Anwendungen mit der echten 32-Bit-Adressierung inkompatibel, und dies wurde als nicht "32-Bit-sauber" bekannt.

Um fortlaufende Systemabstürze zu verhindern, die durch dieses Problem verursacht werden, würde System 6 und frühere Versionen, die auf einem 68020 oder 68030 ausgeführt werden, den Computer in den 24-Bit-Modus zwingen und nur die ersten 8 Megabyte RAM erkennen und beheben, ein offensichtlicher Fehler Maschinen, deren Hardware für die Aufnahme von bis zu 128 MB RAM verkabelt war - und deren Produktliteratur diese Fähigkeit bewarb. Mit System 7 wurde die Mac-Systemsoftware endlich 32-Bit sauber gemacht, aber es gab immer noch das Problem schmutziger ROMs. Das Problem war, dass die Entscheidung für die Verwendung der 24-Bit- oder 32-Bit-Adressierung sehr früh im Startvorgang getroffen werden muss, als die ROM-Routinen den Speichermanager initialisierten, um eine grundlegende Mac-Umgebung einzurichten, in der NuBus-ROMs und Festplattentreiber geladen werden und ausgeführt. Ältere ROMs hatten keine 32-Bit-Speichermanager-Unterstützung und konnten daher nicht im 32-Bit-Modus gestartet werden. Überraschenderweise wurde die erste Lösung für diesen Fehler vom Software-Dienstprogrammunternehmen Connectix veröffentlicht , dessen Produkt MODE32 aus dem Jahr 1991 den Speichermanager neu initialisierte und frühe Teile des Mac-Startvorgangs wiederholte, sodass das System in den 32-Bit-Modus booten und alle verwenden konnte der RAM in der Maschine. Apple lizenzierte die Software später im Jahr 1991 von Connectix und verteilte sie kostenlos. Die Macintosh IIci und späteren Motorola- basierten Macintosh-Computer verfügten über saubere 32-Bit-ROMs.

Es dauerte eine Weile, bis Anwendungen aktualisiert wurden, um alle 24-Bit-Abhängigkeiten zu entfernen, und System 7 bot eine Möglichkeit, in den 24-Bit-Modus zurückzukehren, wenn Anwendungsinkompatibilitäten festgestellt wurden. Zum Zeitpunkt der Migration auf PowerPC und System 7.1.2 war die 32-Bit-Sauberkeit für die Erstellung nativer Anwendungen obligatorisch, und noch später konnten Motorola 68040- basierte Macs den 24-Bit-Modus nicht unterstützen.

Objektorientierung

Der Aufstieg objektorientierter Sprachen für die Programmierung des Mac - zuerst Object Pascal , später C ++ - verursachte ebenfalls Probleme für das verwendete Speichermodell. Auf den ersten Blick erscheint es natürlich, dass Objekte über Handles implementiert werden, um den Vorteil der Verlagerung zu erzielen. Diese Sprachen, wie sie ursprünglich entworfen wurden, verwendeten Zeiger für Objekte, was zu Fragmentierungsproblemen führen würde. Eine Lösung, die von den THINK- Compilern (später Symantec ) implementiert wurde , bestand darin, Handles intern für Objekte zu verwenden, aber eine Zeigersyntax zu verwenden, um auf sie zuzugreifen. Dies schien zunächst eine gute Idee zu sein, aber bald traten tiefe Probleme auf, da Programmierer nicht erkennen konnten, ob es sich um einen verschiebbaren oder festen Block handelte, und daher nicht wissen konnten, ob sie die Aufgabe übernehmen sollten, Objekte zu sperren oder nicht. Unnötig zu erwähnen, dass dies zu einer großen Anzahl von Fehlern und Problemen bei diesen frühen Objektimplementierungen führte. Spätere Compiler versuchten dies nicht, sondern verwendeten echte Zeiger und implementierten häufig ihre eigenen Speicherzuweisungsschemata, um das Mac OS-Speichermodell zu umgehen.

Während das Mac OS-Speichermodell mit all seinen inhärenten Problemen aufgrund schwerwiegender Einschränkungen der Anwendungskompatibilität bis hin zu Mac OS 9 so blieb , bedeutete die zunehmende Verfügbarkeit von billigem RAM, dass die meisten Benutzer im Großen und Ganzen ein Upgrade aus a durchführen konnten Ecke. Der Speicher wurde nicht effizient genutzt, aber er war so reichlich vorhanden, dass das Problem nie kritisch wurde. Dies ist insofern ironisch, als der Zweck des ursprünglichen Entwurfs darin bestand, die Verwendung sehr begrenzter Speichermengen zu maximieren. Mac OS X hat das gesamte Schema endgültig abgeschafft und ein modernes, spärliches virtuelles Speicherschema implementiert . Eine Teilmenge der älteren Speichermodell-APIs ist aus Kompatibilitätsgründen als Teil von Carbon noch vorhanden , wird jedoch dem modernen Speichermanager (einer thread-sicheren malloc Implementierung) darunter zugeordnet. Apple empfiehlt die Verwendung von Mac OS X- Code malloc und free "fast ausschließlich".

Verweise

Externe Links