La gestione della memoria in Macintosh

Con questo articolo inizierò una serie di post articolati sullo sviluppo del Mac OS da quel gennaio '84 fino ai giorni di Mac OS X.
Vista la vastità e la complessità del tema ristringeremo il campo d'azione a una delle parti essenziali del sistema, le API per lo sviluppo software.
Possiamo distinguere tre grandi famiglie (una distinzione che come vedremo più avanti risulta a volte troppo forzata o troppo labile, ma che ci aiuterà a capire meglio gli argomenti trattati): Mac OS ToolBox, Carbon e Cocoa.

 

INDICE:
- Gli anni della nascita
- La frammentazione della memoria
- L'arrivo del MultiFinder
- 32bit e 32bit-clean
- La programmazione OOP

GLI ANNI DELLA NASCITA
Ma prima ancora di iniziare dobbiamo tornare molto indietro nel tempo, e più precisamente ai tempi di Macintosh e della sua gestione della memoria.
Storicamente il Mac è stato sempre diverso dal PC, sia per la qualità del prodotto che per la professionalità. Tuttavia una notevole differenza c'era anche con la gestione della memoria, nella quale il Mac OS (che a quei tempi era System) persisteva nelle proprie scelte.
Nel corso degli anni la tecnica che andremo a descrivere è stata oggetto di forti discussioni e aspre critiche, fino a che, con l'arrivo di OS X è stata definitivamente abbandonata in favore di tecnologie più moderne.
Il problema iniziale degli sviluppatori Apple era quello di utilizzare nel migliore dei modi i 128Kb di RAM messi a disposizione dalla macchina. Visto che a quei tempi soltanto una applicazione alla volte poteva essere attiva sul sistema, e non c'era la possibilità di un storage secondario, i designer implementarono una tecnica semplice ma molto funzionale adatta a questo particolare caso, ma che tuttavia, deficitando di una buona scalabilità, fù oggetto di problemi negli anni successivi.

LA FRAMMENTAZIONE DELLA MEMORIA

Uno dei problemi è stato quello della frammentazione della RAM.
La frammentazione della memoria è un pò quello che accade con la memoria di massa. L'allocazione e la deallocazione ripetuta della memoria può portare alla formazione di piccole zone isolate libere che se sommate possono anche riuscire a soddisfare una possibile richiesta, ma che a conti fatti, una per volta sono praticamente inutili. Questo problema è stato risolto con l'introduzione del concetto di handle riallocabile, ovvero la possibilità di muovere i dati nella memoria senza invalidare l'handle di riferimento alla memoria (l'handle è un puntatore inserito insieme ad altri handle ognuno dei quali punta verso i dati all'interno della cosidetta Master Pointer Block - MPB). In questo modo si semplifica il processo di "compressione" della memoria (ovvero un riutilizzo intelligente dello spazio e delle zone isolate di memoria).

La compattazione non è sempre possibile: non si può realizzare se la rilocazione è statica ed è fatta nella fase di assemblaggio e caricamento. Se gli indirizzi sono rilocati dinamicamente, la rilocazione consiste nel solo spostamento del programma e dei dati, e quindi la modifica del registro di rilocazione in modo che rifletta il nuovo indirizzo di base. La compattazione è eseguita e calcolata tramite diversi algoritmi di compattazione (può essere ignorata nel caso i costi siano proibitivi); il più semplici consiste nello spostare tutti i processi verso un'estremità della memoria, mentre tutti i buchi vengono spostati nell'altra direzione formando un grosso buco di memoria. Il metodo è ovviamente assai oneroso, per cui negli anni avvenire ci si è spostati sulla paginazione e segmentazione

Il computer riserva di suo due aree disponibili a questo genere di modifiche, il system heap (per Mac OS) e application heap dedicato ai software aggiuntivi. Una tecnica che funziona egregiamente fintanto che si ha una sola applicazione in running sul sistema riducendo parecchio la frammentazione.
Il problema è che la system heap non è protetta dalle applicazioni (memoria protetta) ed è facile e frequente che le applicazioni possano arrivare ad occupare o modificare la zona di sistema portando a disastrosi crash della macchina.
Inoltre questo genere di approccio porta i programmatori verso facili errori: il fatto che questi blocchi siano trasferibili in altre zone potrebbe non garantire al programmatore la validità degli handle attraverso le chiamate che possono causare spostamento della memoria stessa.

L'ARRIVO DEL MULTIFINDER

La situazione cambiò con l'arrivo del MultiFinder, ovvero la possibilità di far girare all'interno del Mac più applicazioni alla volta. Purtroppo però per questioni di compatibilità Apple fu forzata a mantenere uno schema di gestione simile dove ogni applicazioni alloca il suo proprio heap in base alla memoria disponibile. Il fatto che questa quantità poteva anche non essere necessaria per alcuni tipi di applicazioni (un esempio su tutti Photoshop) portò Apple a consentirne la modifica anche da parte dell'utente stesso (tramite mela-i sull'applicazione stessa, gli utenti Mac di lungo corso ne sanno qualcosa).
Tutto questo, è facile immaginarlo, cozzava molto col concetto friendly del Mac; tuttavia il problema più grosso era quello dell'inefficenza stessa della tecnica (è molto probabile infatti che buona parte della memoria rimanesse occupata ma del tutto inutilizzata).
Il MultiFinder fu introdotto con il System 7; ci furono vari tentativi di aggirare queste limitazioni tecniche ma per buona parte fallirono miseramente (ad esempio l'utilizzo di una memoria temporanea dove appoggiarsi fu talmente impopolare tra gli sviluppatori che venne abbandonato praticamente subito).
Si provò anche con una prima bozza di memoria virtuale: l'applicazione poteva ricorrere all'hard disk in mancanza di memoria, una tecnica usata anche oggi - swap - ma che per un Mac 68K diventava solo un modo per rallentare ancora più la macchina.
L'utilizzo della MMU (Memory Managment Unit - componenti hardware in grado di gestire le richieste di accesso alla memoria generate dalla macchina: una MMU in particolare gestisci gli indirizzi virtuali, fisici, la gestione della memoria protetta, la cache del sistema e la commutazione del bus) non venne mai preso in considerazione da Apple fino all'introduzione di Mac OS X, benchè ci furono anche tentativi di terze parti - come Optimem - che cercherano di tappare una così grande falla.

32 BIT E 32 BIT-CLEAN

L'arrivo dei 32 bit portò un nuovo sconvolgimento ai ragazzi di Cupertino. Originariamente il Macintosh aveva 128Kb e un limite di 512Kb. Più avanti questo venne aumentato a 4MB (con il Plus), tuttavia la CPU utilizzata era un MC 68000 che non era un vero processore a 32 bit (aveva infatti soltanto 24 linee di indirizzi). Benchè la memoria gestibile fosse quindi 16MB, per problemi di gestione della mappa di memoria il limite fu imposto via software a 8MB (4+4 per RAM e ROM).
Vista la penuria di quantità di memoria i progettisti decisero di utilizzare al massimo ogni singolo byte di ogni indirizzo (in particolare gli 8 bit più alti di ogni puntatore 32 vennerò usati per gestire "questioni interne"). La sfruttamento e il risparmio massimo adottato però portarono a dei problemi quando Apple decise di introdurre con le proprie macchine il processore MC 68020, un vero processore a 32 bit.
In questa architettura quelli che prima erano i bit meno significativi si ribaltarono portando a grossi problemi di indirizzamento. Questo costrinse il team di sviluppo a ridisegnare parzialmente la gestione della memoria creando due classi di applicazioni: 32bit e 32bit-clean (veri) con conseguenti duplici API di gestione (senza considerare che alcuni programmatori continuavano ad accedere a queste porzioni di indirizzi direttamente, senza utilizzare le funzioni sicure preposte).
Alcune macchine vennero forzate da Apple a lavorare in modalità 24 bit al fine di evitare possibili problemi; soltanto molto tempo dopo, con l'avvento del System 7 l'OS si prese carico di forzare i 24bit in caso di problemi e nel contempo poter utilizzare appieno il processore in caso di applicazionbe nativa.

LA PROGRAMMAZIONE OOP

Un altro problema per la scarsa gestione della memoria di Macintosh arrivò con l'introduzione della programmazione OOP e dei primi linguaggi orientati agli oggetto: Object Pascal e C++. Per loro natura questi linguaggi possono utilizzare i puntatori agli oggetti e quindi portare a problemi di frammentazione. Una soluzione al problema fu adottata dai compilatori della THINK (l'attuale Symantec) fu quella di usare una sintatti puntatore per accedere agli handle degli oggetti. Tuttavia questa idea portò più confusione che altro e si tornò presto all'uso di puntatori reali e ad un uso dell'allocazione personale per ogni applicazione (nel tentativo di aggirare le limitazione della gestione della memoria del Mac OS).

Questo modello di gestione della memoria rimase in uso fino a Mac OS 9 soprattutto per questioni di compatibilità. Benchè la progettazione dello schema di memoria fosse sempre limitativa e problematica non divenne mai così critica per giungere a decisioni estreme. Attualmente Mac OS X utilizza uno schema profondamente diverso benchè alcune API per la gestione della memoria persistano ancora nelle librerie Carbon.

[tags] Mac OS Memory Managment, Macintosh, Storia Macintosh, Gestione Memoria Macintosh[/tags]