14.07.2013 Aufrufe

Virtueller Speicher Einführung

Virtueller Speicher Einführung

Virtueller Speicher Einführung

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

Vorwort:<br />

<strong>Virtueller</strong> <strong>Speicher</strong><br />

Die virtuelle <strong>Speicher</strong>technik besitzt ein sehr breites Spektrum an verschiedenen<br />

Realisierungen. Es gibt praktisch keine zwei Architekturen, welche genau die gleiche<br />

Implementierung der virtuellen <strong>Speicher</strong>technik besitzen. Es würde deshalb den Rahmen<br />

sprengen auf jedes Detail einzugehen. Es sollen deshalb vielmehr die Grundideen und<br />

Prinzipien der virtuellen <strong>Speicher</strong>technik vermittelt werden.<br />

• Inhalt<br />

• <strong>Einführung</strong><br />

o Motivation<br />

• Allgemeine Prinzipien<br />

o Prinzip der Lokalität<br />

o <strong>Speicher</strong>hierarchie<br />

• Adreßumsetzung<br />

o Mapping<br />

o Seitentafel (page table)<br />

Mehrstufige Seitentafel<br />

Invertierte Seitentafel<br />

• Seitenverwaltung<br />

o Blockplazierung<br />

o Blockersetzung<br />

o Schreibstrategie<br />

o Seitenfehler<br />

o Seitengröße<br />

o Seitengrößenerweiterung (page size extension)<br />

• Adreßumsetzungspuffer (TLB)<br />

• <strong>Speicher</strong>schutz<br />

• Zusammenfassung<br />

• Literatur<br />

• Über dieses Dokument ...<br />

<strong>Einführung</strong><br />

1962 hatte Kilburn die Idee, die zwei Ebenen Kern- und Trommelspeicher automatisch zu<br />

verwalten und als eine Ebene erscheinen zu lassen. Er demonstrierte seine Idee eines<br />

virtuellen <strong>Speicher</strong>s an einem Atlas-Computer an der University of Manchester [1].


Zuerst wurde die virtuelle <strong>Speicher</strong>technik nur in Großrechnern implementiert. Erst seit<br />

Entwicklung des 386-Prozessor (interne MMU ) findet sie auch in der Welt des PCs<br />

Verwendung. Seit über 10 Jahren ist die virtuelle <strong>Speicher</strong>technik in jeder Workstation<br />

implementiert. Es gibt aber spezielle Systeme (Embedded Systems) die keinen virtuellen<br />

<strong>Speicher</strong> benutzen, da sie besonders zeiteffektive Serverfunktionen durchführen.<br />

Die MMU (memory management unit) ist ein Bestandteil von Mikroprozessoren, der<br />

die internen Register und <strong>Speicher</strong>bereiche wie z.B. virtuellen <strong>Speicher</strong> und<br />

Prozessor-Caches steuert.<br />

.<br />

Motivation<br />

Der Wunsch von Programmierern ist es, über einen scheinbar unbeschränkt großen <strong>Speicher</strong><br />

zu verfügen, um nicht darauf achten zu müssen, daß die Programme zu groß werden.<br />

Deswegen benötigt man eine <strong>Speicher</strong>technik, welche mehr Code und Daten im <strong>Speicher</strong><br />

unterbringen kann als realer <strong>Speicher</strong> (Hauptspeicher) vorhanden ist.<br />

Ein weiteres Problem der <strong>Speicher</strong>verwaltung ist die Fragmentierung des realen <strong>Speicher</strong>s, da<br />

Code und Daten eines Prozesses fortlaufende Adressen haben müssen. Dies kann dazu führen,<br />

daß für einen Prozeß kein Platz mehr frei ist, obwohl noch an anderer Stelle Platz im <strong>Speicher</strong><br />

frei ist. Dies wird in Abb. 1.1 dargestellt.<br />

Abbildung 1.1: Ohne virtuellen <strong>Speicher</strong> hat Prozeß 2 zuwenig Platz, um noch weitere Seiten<br />

zu benutzen. Mit virtuellem <strong>Speicher</strong> kann er Platz an einer anderen freien Stelle im<br />

Hauptspeicher verwenden.<br />

In den heutigen Multiprocessing-Betriebssystemen laufen mehrere Prozesse gleichzeitig.<br />

Dabei ist ein Schutz von Daten und Code der einzelnen Prozesse nötig, sowie die Möglichkeit<br />

der Kommunikation zwischen den Prozessen und der gemeinsamen Nutzung von Code und


Daten. Dazu muß der physikalische <strong>Speicher</strong> auch auf mehrere Prozesse aufgeteilt werden<br />

können, um sinnvoll mit Multiprocessing zu arbeiten. Die virtuelle <strong>Speicher</strong>technik löst diese<br />

Probleme, indem sie die Ebenen Hauptspeicher und sekundären <strong>Speicher</strong> automatisch und<br />

geschickt steuert.<br />

Prinzip der Lokalität<br />

Die meisten Programme greifen nicht gleichmäßig auf ihren Code und ihre Daten zu [2]. Die<br />

Untersuchung dieser Feststellung führt zum Prinzip der Lokalität, daß sich in zeitliche und<br />

räumliche Lokalität aufteilt.<br />

• räumliche Lokalität: Nachdem auf eine Adresse zugegriffen wurde, erfolgt<br />

wahrscheinlich ein Zugriff auf eine benachbarte Adresse.<br />

Das linke Beispiel in Abb. 2.1 zeigt die räumliche Lokalität anhand eines<br />

Codestückes. Der lineare Verlauf stellt die normale Programmabarbeitung dar, bei der<br />

der Programmzähler laufend incrementiert wird. Die Wiederholung deutet auf eine<br />

Schleife hin, die vier mal durchlaufen wird. Danach gibt es eine Sprunganweisung und<br />

das Programm wird weiter abgearbeitet.<br />

• zeitliche Lokalität: Nachdem auf eine Adresse zugegriffen wurde, erfolgt<br />

wahrscheinlich bald ein weiterer Zugriff auf dieselbe Adresse.<br />

Das rechte Beispiel von Abb. 2.1 stellt die zeitliche Lokalität dar. Die Quadrate<br />

könnten z.B. Variablen sein. Eine Variable steht immer an der gleichen Adresse, die<br />

Adresse wird aber öfters benutzt um auf den Wert der Variablen zuzugreifen oder um<br />

an der Adresse einen neuen Wert zu speichern.<br />

Abbildung 2.1: Beispiele für räumliche und zeitliche Lokalität.<br />

Das Prinzip der Lokalität ist von großer Bedeutung beim Entwurf einer <strong>Speicher</strong>hierarchie. Es<br />

führt zum Konzept einer auf unterschiedlichen Geschwindigkeiten und Kapazitäten<br />

basierenden Hierarchie.<br />

<strong>Speicher</strong>hierarchie


Eine <strong>Speicher</strong>hierarchie ist eine Organisationsform von <strong>Speicher</strong>n. Die verschiedenen<br />

<strong>Speicher</strong>arten werden in Ebenen aufgeteilt (z.B. Register, Cache, Hauptspeicher und<br />

Festplatte). Jede Ebene ist schneller, kleiner und teurer (Preis pro Byte) als die Ebene darunter<br />

(vgl. Abb. 2.1). Alle Daten einer Ebene sind auch in der Ebene darunter enthalten. Die<br />

kleinste Informationseinheit in einer <strong>Speicher</strong>hierarchie nennt man Block. Zwischen den<br />

Ebenen werden immer nur komplette Blöcke verschoben. Einen Erfolg eines Zugriffs in einer<br />

Ebene nennt man Treffer (hit), einen Mißerfolg Fehlzugriff (miss) (Block nicht in der Ebene).<br />

Die Trefferrate (hit rate) ist der prozentuale Anteil der Treffer an den Zugriffen. Der<br />

prozentuale Anteil der Fehlzugriffe nennt man Fehlzugriffsrate. Das Ziel einer<br />

<strong>Speicher</strong>hierarchie ist es, mit dem großen <strong>Speicher</strong>bereich einer unteren Ebene zu arbeiten<br />

und dieses mit der Geschwindigkeit einer oberen Ebene.<br />

Abbildung 2.2: <strong>Speicher</strong>hierarchie<br />

Mapping<br />

Das Prinzip der virtuellen <strong>Speicher</strong>technik ist die Trennung des Adreßraumes des<br />

Hauptspeichers vom Adreßraum, den die Prozesse benutzen (virtueller Adreßraum). Dabei<br />

kann jeder Prozeß seinen eigenen virtuellen Adreßraum benutzen. Sowohl der virtuelle<br />

<strong>Speicher</strong> als auch der reale <strong>Speicher</strong> werden in Blöcke gleicher Größe aufgeteilt. Beim<br />

virtuellen <strong>Speicher</strong> nennt man die Blöcke Seiten (pages), beim Hauptspeicher Rahmen<br />

(frames). Die Seiten des virtuellen <strong>Speicher</strong>s werden auf die Rahmen im Hauptspeicher<br />

abgebildet (mapping). Dabei ist es egal, auf welchen Rahmen, man kann irgendeinen freien<br />

Rahmen wählen (vgl. Abb. 3.1).


Abbildung 3.1: Abbildung (Mapping) der virtuellen Adreßräume in den Hauptspeicher.<br />

Deshalb kann der Hauptspeicher besser ausgenutzt werden, die Prozesse müssen nicht am<br />

Stück im Hauptspeicher liegen und das Problem der Fragmentierung des Hauptspeichers ist<br />

somit beseitigt. Es kann auch Seiten geben, die auf keinen Rahmen abgebildet werden. Diese<br />

Seiten liegen dann nur auf einem externen <strong>Speicher</strong> (Festplatte). Dies wird ausgenutzt um<br />

einen wesentlich größeren <strong>Speicher</strong>bereich verwenden zu können als Hauptspeicher<br />

vorhanden ist. Wurde früher ein Programm zu groß für den Hauptspeicher war es das Problem<br />

des Programmierers, es irgendwie passend zu machen. Der virtuelle Adreßraum ist nicht nur<br />

größer als der physikalische Adreßraum, sondern kann auch Lücken besitzen (vgl. Abb.3.2).<br />

Die virtuelle <strong>Speicher</strong>technik reduziert auch meistens die Startzeit eines Prozesses, da nicht<br />

der gesamte Code in den Hauptspeicher geladen werden muß, bevor der Prozeß starten kann.<br />

Abbildung 3.2: <strong>Virtueller</strong> <strong>Speicher</strong> > Hauptspeicher<br />

Über die Abbildungsvorschrift läßt sich die Position einer Seite im Hauptspeicher finden. Was<br />

aber wenn man auf eine bestimmte Adresse innerhalb einer Seite zugreifen will? Dazu wird<br />

eine virtuelle Adresse in zwei Hälften unterteilt, der werthöheren Hälfte, der Seitennummer<br />

und der wertniederen Hälfte, dem Offset. Die physikalische Adresse besteht entsprechend aus<br />

Rahmennummer und Offset (vgl. Abb. 3.3). Dabei ist die Seitennummer die Adresse einer<br />

einzelnen Seite im virtuellen <strong>Speicher</strong>. Der Offset ist die Adresse innerhalb einer Seite. Die<br />

Länge des Offsets ist abhängig von der Seitengröße, sie ist genau log2(Seitengröße). Die<br />

Länge der virtuellen Adresse ist architekturabhängig. Sie beträgt z.Z. meistens 32 Bit. Bei der<br />

Länge der physikalischen Adresse kommt es auf den <strong>Speicher</strong>ausbau an. Da der<br />

Hauptspeicher die gleiche Blockgröße wie der virtuelle <strong>Speicher</strong> hat, kann bei der<br />

Adreßumsetzung der Offset der virtuellen Adresse einfach an die Rahmennummer angehängt<br />

werden. Es muß also nur die Seitennummer in die entsprechende Rahmennummer übersetzt<br />

werden. Die Abbildungsvorschrift wird in Form einer Seitentafel implementiert.


Abbildung 3.3: Umwandlung von virtueller in physikalische Adresse. Die Seiten- bzw.<br />

Rahmengröße beträgt 2 12 = 4 KB. Die Anzahl der Rahmen beträgt 2 18 (= 1GB <strong>Speicher</strong>platz)<br />

und die Anzahl der Seiten beträgt 2 20 (= 4 GB <strong>Speicher</strong>platz).<br />

Seitentafel (page table)<br />

Eine Seitentafel oder Seitentabelle ist eine Datenstruktur, die durch die Seitennummern<br />

indexiert wird, d.h. jede Seite muß einen Eintrag in der Seitentafel haben. Die Anfangsadresse<br />

der Seitentafel steht in einem Register, dem Seitentafelregister. Jeder Eintrag der Seitentafel<br />

enthält die Rahmennummer der zugehörigen Seitennummer, falls diese im realen <strong>Speicher</strong> ist,<br />

und eine Verwaltungseinheit mit verschiedenen Steuerbits. Jeder einzelne Eintrag hat eine<br />

Länge von 32 Bit. Durch ein Präsenzbit (Valid-Bit) wird angezeigt, ob sich eine Seite im<br />

Hautspeicher befindet (Valid-Bit gesetzt) oder nicht (Valid-Bit nicht gesetzt). Die Größe der<br />

Seitentafel ist von der Anzahl der Seiten im virtuellen Adreßraum abhängig, z.B. eine<br />

Seitentafel mit einem 32-Bit Adreßraum, 4 KB großen Seiten und 4 Byte pro Eintrag, hat eine<br />

Größe von 4 MB (2 20 x4 Byte). Hat man nun eine virtuelle Adresse, so nimmt man die<br />

Seitennummer und greift auf den entsprechenden Eintrag in der Seitentafel zu (z.B.<br />

Seitenummer 3210 würde ein Zugriff auf den 3210. Eintrag in der Seitentafel bedeuten). Falls<br />

sich die Seite im Hauptspeicher befindet, steht in diesem Eintrag die dazugehörige<br />

Rahmennummer. An diese wird dann der Offset der virtuellen Adresse angehängt, dann kann<br />

mit der entstandenen physikalischen Adresse auf den Hauptspeicher zugegriffen werden. Der<br />

ganze Vorgang ist in Abb. 3.4 graphisch dargestellt.


Abbildung 3.4: Adreßumsetzung mit Seitentafel<br />

Mehrstufige Seitentafel<br />

Es wäre verschwenderisch, so große Seitentafeln die ganze Zeit im Hauptspeicher zu halten.<br />

Deswegen wird meistens eine mehrstufige Seitentafel verwendet, wobei die Seitennummer in<br />

mehrere Teile zerlegt wird. Alle Teile, bis auf den untersten Teil, werden für den Zugriff auf<br />

Seitentafeln verwendet, welche keine Rahmennummer im Eintrag haben, sondern einen<br />

Pointer auf eine andere Seitentafel. Mit dem höchsten Teil der Seitennummer wird ein<br />

Seitentafeleintrag indexiert, dessen Pointer auf eine weitere Seitentafel zeigt. Mit dem<br />

nächsten Teil der Seitennummer wird dann diese Seitentafel indexiert, wodurch man wieder<br />

einen Eintrag mit einem Pointer auf eine andere Seitentafel erhält. Dies wird solange<br />

fortgesetzt, bis man am untersten Teil der Seitennummer angekommen ist. Dieser indexiert<br />

dann einen Seitentafeleintrag mit einer Rahmennummer anstatt einem Pointer. An diese<br />

Rahmennummer muß jetzt nur noch der Offset angehängt werden, um die physikalische<br />

Adresse zu erhalten.<br />

In Abb. 3.5 wird eine 20-Bit Seitennummer in 2x10 Bit aufgeteilt. Mit den oberen 10 Bit wird<br />

auf die Seitentafel, auf die das Seitentafelregister zeigt, zugegriffen. Ist im entsprechenden<br />

Eintrag der Seitentafel ein Nullpointer, so befindet sich der Adreßbereich nicht in Benutzung.<br />

Ansonsten gibt es in dem Eintrag einen Pointer auf eine normale Seitentafel, auf welche mit<br />

den unteren 10 Bit zugegriffen wird. Der indexierte Eintrag enthält dann, falls das Valid-Bit<br />

gesetzt ist, die Rahmennummer, ansonsten gibt es einen Seitenfehler. Die mehrstufige<br />

Seitentafel hat den Vorteil, daß alle Seitentafeln selber wieder in 4 KB große Seiten passen (4<br />

Byte x 2 10 Einträge, bei 4 Byte großen Einträgen) und damit auf externen <strong>Speicher</strong><br />

ausgelagert werden können. Die Seitentafel mit den Pointern bleibt natürlich im<br />

Hauptspeicher.


Abbildung 3.5: Mehrstufige Seitentafel<br />

Invertierte Seitentafel<br />

Eine andere Möglichkeit, die Größe der Seitentafel zu reduzieren, ist die Benutzung einer<br />

invertierten Seitentafel (inverted page table). Die Idee dabei ist es, einen Eintrag pro Rahmen<br />

anstatt einen pro Seite in der Seitentafel zu verwenden. Dazu benötigt man eine Hash-<br />

Funktion, die die virtuellen Adressen auf die Rahmen aufteilt. Die Größe der Seitentafel ist<br />

jetzt nur noch von der Zahl der Rahmen im Hauptspeicher abhängig, welche normal<br />

wesentlich kleiner ist als die Anzahl der virtuellen Seiten, so daß man meist die ganze<br />

Seitentafel im Hauptspeicher halten kann. Ein Beispiel einer Architektur, die eine invertierte<br />

Seitentafel verwendet, ist der PowerPC (IBM/Motorola).<br />

Blockplazierung<br />

Die virtuelle <strong>Speicher</strong>technik hat sehr hohe Zugriffszeiten bei Seitenfehlern, da die Seite nicht<br />

im Hauptspeicher ist und ein Zugriff auf Festplatte erfolgen muß (vgl. Tabelle 4.1). Deshalb<br />

versucht das Betriebssystem die Blöcke möglichst geschickt zu plazieren, um weniger<br />

Seitenfehler zu verursachen. Dazu nimmt man auch kompliziertere Plazierungsalgorithmen in<br />

Kauf. Man entscheidet sich deswegen für vollassoziative Blockplazierung, bei der die Blöcke<br />

irgendwo im Hauptspeicher plaziert werden können.


Blockersetzung<br />

Wenn alle Rahmen des Hauptspeichers belegt sind und eine neue Seite eingeräumt werden<br />

soll, muß irgendeine Seite auf den externen <strong>Speicher</strong> ausgeräumt werden. Um zu bestimmen,<br />

welcher Block ersetzt wird, gibt es folgende Ersetzungsalgorithmen:<br />

• Beim FIFO-Algorithmus (first in first out) wird der zuerst eingespeicherte Block<br />

ersetzt. Es gibt viele Beispiele, bei denen die Anwendung des FIFO-Algorithmuses<br />

schlecht ist, z.B. bei großen Schleifen kann es passieren, daß der Algorithmus die<br />

Adressen des Beginns der Schleife am Schluß der Schleife wieder austauscht.<br />

Deswegen wird er nur selten implementiert.<br />

• Beim LIFO-Algorithmus (last in first out) wird der zuletzt eingespeicherte Block<br />

ersetzt. Der Algorithmus wiederspricht dem Prinzip der Lokalität und wird nicht<br />

benutzt.<br />

• Beim LRU-Algorithmus (least recently used) wird der am längsten ungenutzte Block<br />

ersetzt. Der LRU-Algorithmus liefert sehr gute Ergebnisse, braucht aber eine<br />

umfangreiche Verwaltung, falls er explizit den am längsten unbenutzten Block<br />

bestimmen soll.<br />

• Beim LFU-Algorithmus (least frequently used) wird der am wenigsten benutze Block<br />

ersetzt. Der LFU-Algorithmus ist sehr ähnlich wie der LRU-Algorithmus. Auch er<br />

liefert sehr gute Ergebnisse, braucht aber auch eine umfangreiche Verwaltung, falls er<br />

explizit den am wenigsten benutzten Block bestimmen soll. Deswegen wird meist ein<br />

vereinfachter Algorithmus verwendet, der nur wenige Zustände zwischen oft und<br />

wenig benutzten Seiten hat.<br />

• Beim Random-Algorithmus wird ein zufällig gewählter Block ersetzt. Es kann dabei<br />

im schlechtesten Fall auch gerade der Block ersetzt werden, den man gerade<br />

verwendet hat. Im Mittel liefert er doch ein gutes Ergebnis und ist recht einfach zu<br />

implementieren.<br />

Besonders effektiv arbeitet das Betriebssystem, wenn mehrere Blöcke auf einmal ersetzt<br />

werden, da der E/A Aufwand bei größeren Schreib- bzw. Lesevorgängen im Verhältnis zu<br />

mehreren kleinen günstiger ist.<br />

Fast immer benutzen die Betriebssysteme eine Approximation des LRU-Algorithmus. Man<br />

benutzt Use-Bits in der Verwaltungseinheit der Seitentafel, welche beim Seitenzugriff gesetzt<br />

und periodisch wieder gelöscht werden. Es kann dann zu einer bestimmten Zeit gesagt<br />

werden, ob auf eine Seite innerhalb einer Periode zugegriffen wurde. Aus allen Seiten mit<br />

ungesetztem Use-Bit wird dann eine ausgewählt, die ersetzt wird. Am günstigsten ist immer<br />

eine Seite mit ungesetztem Dirty-Bit zu ersetzen, weil diese nicht zurückgeschrieben werden<br />

muß. Da bei diesem vereinfachten Algorithmus die am seltesten genutzen Seiten den am<br />

längsten nicht genutzten Seiten entsprechen, ist diese Methode gleichzeitig eine Art<br />

vereinfachter LFU-Algorithmus.<br />

Schreibstrategie<br />

• falls alle Seiten auch im externen <strong>Speicher</strong> sind<br />

Das Schreiben auf externen <strong>Speicher</strong> benötigt hunderttausende Taktzyklen, deswegen<br />

wäre es viel zu langsam, alle Änderungen direkt auf Platte zu schreiben. Die


Schreibstrategie ist also write-back, d.h. die Seiten werden erst bei Ersetzung auf den<br />

externen <strong>Speicher</strong> zurückgeschrieben. Um nur die Blöcke zurückzuschreiben, die<br />

verändert wurden, wird ein Dirty-Bit in der Verwaltungseinheit der Seitentafel<br />

benutzt. Ist es nicht gesetzt, wurde die Seite nicht geändert und die Seite muß nicht<br />

einmal zurückgeschrieben werden, wenn sie ersetzt wird. Ist das Dirty-Bit gesetzt,<br />

wurde die Seite verändert und ist bei der Ersetzung zurückzuschreiben.<br />

• falls nur Seiten die nicht im Hauptspeicher sind im externen <strong>Speicher</strong> sind<br />

Hierbei werden die Seiten einfach getauscht. Wenn eine Seite in den Hauptspeicher<br />

eingeräumt werden soll, wird einfach eine nach einem Ersetzungsalgorithmus<br />

ausgewählte Seite vom Hauptspeicher in den externen <strong>Speicher</strong> ausgeräumt und dann<br />

die gewünschte Seite in den Hauptspeicher eingeräumt. Diese befindet sich danach<br />

aber nicht mehr auf externem <strong>Speicher</strong>. Die Methode ist ein wenig langsamer, aber sie<br />

hat einen größeren virtuellen <strong>Speicher</strong>bereich; z.B. bei 64 MB Hauptspeicher und 128<br />

MB externen <strong>Speicher</strong> hat sie 196 MB virtuellen <strong>Speicher</strong> anstatt 128 MB bei der<br />

oberen Methode. Außerdem kann die Methode nahezu gleich schnell gemacht werden,<br />

indem darauf geachtet wird, daß man, sobald die Anzahl freier Seiten unter eine<br />

bestimmte untere Schranke sinkt, wieder freie Seiten schafft, bis eine bestimmte obere<br />

Schranke an freien Seiten erreicht wird.<br />

Seitenfehler<br />

Wird auf einen Eintrag in der Seitentafel zugegriffen, dessen Valid-Bit auf null ist, wird eine<br />

Ausnahme geworfen. Der Seitenüberwacher, ein Teil des Betriebssystems, der für das<br />

Seitenmanagement verantwortlich ist, muß die Seite nun in den Hauptspeicher holen. Die<br />

Auswahl der zu ersetzenden Seite erfolgt mit Hilfe eines Ersetzungsalgorithmuses. Hat sie ein<br />

gesetztes Dirty-Bit muß sie zuerst noch auf externen <strong>Speicher</strong> geschrieben werden. Die Seite,<br />

die eingeräumt werden soll, wird dann über eine externe Seitentafel gefunden. In ihr steht für<br />

jede Seite die Adresse, auf der sie sich auf dem externen <strong>Speicher</strong> befindet (vgl. Abb. 4.1).<br />

Nach dem Einräumen der Seite in den Hauptspeicher wird das dazugehörige Valid-Bit im<br />

entsprechenden Seitentafeleintrag gesetzt. Da der <strong>Speicher</strong>transfer sehr viel Zeit benötigt,<br />

muß die CPU in der Lage sein, während der Blockersetzung einen anderen Prozeß zu<br />

bearbeiten, falls einer vorhanden und von dem Seitenfehler nicht ebenfalls betroffen ist. Ist<br />

der <strong>Speicher</strong>transfer beendet, kann dann der vorherige Prozeß wiederhergestellt und weiter<br />

abgearbeitet werden. In der Praxis kommt ein Seitenfehler nur mit einer Wahrscheinlichkeit<br />

von 0.0001% vor, so daß man gut mit virtuellem <strong>Speicher</strong> arbeiten kann.


Abbildung 4.1: Seitenfehler<br />

Seitengröße<br />

Ein wichtiger Architekturparameter für virtuellen <strong>Speicher</strong> ist die Seitengröße. Einige Punkte<br />

sprechen für große, einige für kleine Seiten. Hier sind die Hauptpunkte:<br />

• Je größer die Seiten, desto kleiner die Seitentafel. Dadurch kann <strong>Speicher</strong> gespart<br />

werden.<br />

• Die Übertragung von großen Seiten ist effektiver, da der Aufwand für das Ein- und<br />

Ausräumen von Seiten sehr groß ist. Es ist besser einmal 4 KB zu übertragen als 4x1<br />

KB.<br />

• Für kleine Seiten spricht, daß diese nicht soviel <strong>Speicher</strong> verschwenden. Wenn ein<br />

Prozeß z.B. 5 KB benötigt, braucht er zwei Seiten (bei einer Seitengröße von 4 KB).<br />

Er hat also insgesamt 8 KB <strong>Speicher</strong>platz verbraucht, obwohl die letzte Seite noch 3<br />

KB frei hat. Diese können aber nicht anderweitig verwendet werden, was als interne<br />

Fragmentierung bezeichnet wird.<br />

• Zu große Seiten können unter Umständen E/A-Bandbreite verschwenden.<br />

Am häufigsten werden 4 KB große Seiten verwendet, da diese einen guten Kompromiß aus<br />

den verschiedenen Punkten bilden und die Adreßumsetzung dabei erfahrungsgemäß gut<br />

funktioniert.<br />

Seitengrößenerweiterung (page size<br />

extension)<br />

Die meisten Architekturen, die virtuellen <strong>Speicher</strong> implementieren, erlauben es, außer der<br />

Standard-Seitengröße, besonders große Seiten zu verwenden (z.B. die Pentiumarchitektur).<br />

Dies geschieht mit der Hilfe eines PSE-Bit (Page Size Extension-Bit) in der<br />

Verwaltungseinheit der Seitentafel. Ist es nicht gesetzt, werden die Standardseiten verwendet,<br />

falls es gesetzt ist, wird eine große Seite benutzt. Das findet vor allem Anwendung bei der<br />

Abbildung von Hardware Ein-/Ausgabebereichen in den <strong>Speicher</strong> (Memory Mapped I/O),


weil dabei oft ein sehr großer, kontinuierlicher <strong>Speicher</strong>bereich benötigt wird, z.B. bei<br />

Grafikkarten. Anwendung findet die Technik z.B. in der Pentiumarchitektur [3], die es erlaubt<br />

4 MB große Seiten, anstatt 4 KB große Seiten zu verwenden, falls das PSE-Bit gesetzt ist. Der<br />

Vorteil der Seitengrößenerweiterung ist, daß man weniger Verwaltungsaufwand hat. Es kann<br />

z.B. eine 4 MB große Seite, die nur einen Eintrag in der Seitetafel benötigt, benutzt werden,<br />

anstatt 1024 Einträge, die man bei einer Seitengröße von 4 KB benötigen würde.<br />

Adreßumsetzungspuffer (TLB)<br />

Die Adreßumsetzung mit Hilfe der Seitentafel ist mit zusätzlichen Hauptspeicherzugriffen<br />

verbunden. Man benötigt erst zwei Hauptspeicherzugriffe für die Adreßumsetzung (bei<br />

zweistufiger Seitentafel) und erst dann erfolgt der eigentliche Hauptspeicherzugriff, falls die<br />

Seite den Zustand valid hat. Um überhaupt sinnvoll mit virtuellem <strong>Speicher</strong> arbeiten zu<br />

können, muß daher die Adreßumsetzung beschleunigt werden. Man greift dabei wieder auf<br />

das Prinzip der Lokalität zu. Es ist wahrscheinlich, daß die Adresse, die gerade übersetzt<br />

wurde, nochmal benutzt wird oder auf eine benachbarte zugegriffen wird. Deshalb wird ein<br />

zusätzlicher Schnellspeicher verwendet, der die letzten Umsetzungen von Seitennummern in<br />

Rahmennummern enthält. Dieser Schnellspeicher wird in der Fachsprache TLB (translationlookaside<br />

buffer) genannt. Er besteht meist aus 64-Bit Einträgen, die<br />

Verwaltungsinfomationen, ein Tag und eine Rahmennummer beinhalten. Das Tag beinhaltet<br />

die Seitennummer zur Rahmennummer im zugehörigen Eintrag. Es wird benötigt, weil nicht<br />

jede Seitennummer im TLB Platz findet und somit nicht direkt über die Seitennummer<br />

indexiert werden kann, wie bei der Seitentafel.<br />

Abbildung 5.1: Funktionsweise eines TLB<br />

Bei jeder Adreßumsetzung wird nun die zu übersetzende Seitennummer mit den einzelnen<br />

Tags verglichen. Stimmen sie überein und ist das Valid-Bit des Eintrags gesetzt, so hat man<br />

einen TLB-Treffer und kann die Rahmennummer direkt aus dem Eintrag im TLB lesen, ohne<br />

einen Zugriff auf die Seitentafel. Nun muß nur noch der Offset von der virtuellen Adresse<br />

angehängt werden und dann kann der Hauptspeicherzugriff erfolgen. Ist die Seite aber nicht


im TLB oder das Valid-Bit des betreffenden Eintrags auf Null gesetzt, dann muß die<br />

Umsetzung der Adresse über die Seitentafel erfolgen. Die Umsetzung wird danach in den<br />

TLB eingeräumt, so daß beim nächsten Zugriff auf die Seite die Umsetzung schon im TLB<br />

ist, falls sie nicht schon wieder ersetzt worden ist. Der gesamte Vorgang ist in Abb. 5.1<br />

nochmals graphisch dargestellt. Für die Ersetzung im TLB werden meist eine Approximation<br />

des LRU- oder der Random-Algorithmus verwendet. Die Blockplazierung erfolgt<br />

vollassoziativ oder set-assoziativ. Set-assoziativ bedeutet, daß eine Seitennummer nur in<br />

einen bestimmten Bereich (set) des TLB abgebildet werden kann. Nach dem<br />

Konsistenzkriterium kann es einen TLB-Treffer nur geben, falls es auch einen Treffer in der<br />

Seitentafel geben würde (vgl. Tabelle 5.1). Ein TLB kann zwischen 32 und 4096 Einträge<br />

besitzen. Die Zugriffszeit bei einem Treffer beträgt 1 Taktzyklus, bei einem Fehler beträgt sie<br />

10 bis 30 Taktzyklen. Die Fehlerrate liegt zwischen 0.01% und 1%.<br />

<strong>Speicher</strong>schutz<br />

Weil zur selben Zeit mehrere Prozesse ablaufen und es verschiedene Benutzer gibt, muß ein<br />

Weg zum sicheren Schutz und Teilen von Code und Daten zwischen den einzelnen Prozessen<br />

gefunden werden. Dabei muß das Betriebssystem in der Lage sein, jederzeit von einem<br />

Prozeß in einen anderen umschalten zu können und die verschiedenen Prozesse gleichzeitig<br />

im Hauptspeicher zu halten. Es gibt verschiedene Methoden den <strong>Speicher</strong> zwischen den<br />

Prozessen aufzuteilen. Eine ist es, den Hauptspeicher in verschiedene Regionen für die<br />

Benutzerprozesse aufzuteilen. Die Regionen können verschiedene Größen haben. Dabei muß<br />

der Überwacher darauf achten, daß die Ressourcen unter Berücksichtigung einer<br />

ökonomischen Rechnerauslastung auf die Prozesse verteilt werden. Der Überwacher belegt<br />

einen festen, gegen Schreibzugriffe von Nutzerprozessen geschützten <strong>Speicher</strong>bereich, der in<br />

den realen <strong>Speicher</strong> abgebildet wird (vgl. Abb.6.1). Die Seiten der Regionen werden auf die<br />

restlichen Rahmen abgebildet bzw. auf den externen <strong>Speicher</strong>, falls nicht genügend Platz im<br />

Hauptspeicher ist.


Abbildung 6.1: Abbildung eines geschützten virtuellen <strong>Speicher</strong>s in den realen <strong>Speicher</strong>.<br />

Eine andere Möglichkeit ist es, jedem Prozeß den gesamten virtuellen Adreßraum zur<br />

Verfügung zu stellen. Ein Teil des virtuellen Adreßraumes von jedem Nutzerprozeß wird vom<br />

Überwacher belegt, es existiert aber nur eine Kopie davon im Hauptspeicher (vgl. Abb.6.2).<br />

Durch die Prozeß-ID sind die Adressen eindeutig bestimmt. Das ist vor allem für den TLB<br />

wichtig denn es wäre ineffektiv den TLB bei jeder Prozeßumschaltung ganz zu löschen, man<br />

könnte seine volle Kapazität gar nicht ausnutzen. Deswegen kann man einfach die Prozeß-ID<br />

im TLB-Eintrag verwenden, um damit die Einträge, die zu anderen Prozessen gehören, zu<br />

schützen, indem man die Prozeß-ID des aktiven Prozesses mit dem ID-Eintrag vergleicht.<br />

Abbildung 6.2: Seitenschutz, bei dem jeder Prozeß den vollen Adreßraum zur Verfügung<br />

stehen hat.<br />

Die Aufteilung des Hauptspeichers mit diesen beiden Methoden macht einen<br />

Schutzmechanismus nötig, um einen Prozeß zu hindern, einen anderen zu manipulieren oder<br />

seine Daten zu lesen. Andererseits sollen die Prozesse auch miteinander kommunizieren und<br />

auf Daten und Code gemeinsam zugreifen können. Am einfachsten läßt sich der Schutz mit<br />

Steuerbits in der Seitentafel realisieren. Man benutzt dafür z.B. ein Schreibschutz-Bit, um<br />

versehentliches Überschreiben von Code zu verhindern. Je nach Betriebssystem werden auch<br />

verschiedene Zugriffschutzbits für die verschiedenen Benutzerebenen verwendet und ein<br />

User-/Kernel-Bit, um zwischen Zugriffe von Benutzern oder vom Betriebssystem zu<br />

unterscheiden. Die Seitentafel darf nur im Kernel-Modus verändert werden, weil sonst der<br />

<strong>Speicher</strong>schutz nicht mehr funktionieren würde. Bei der gemeinsamen Nutzung von Code und<br />

Daten wird ein entsprechender Seitentafeleintrag in jedem Adreßraum eines Prozesses der auf


den Code und die Daten zugreifen können soll, eingerichtet, der auf den selben Rahmen im<br />

physikalischen <strong>Speicher</strong> zeigt. <strong>Speicher</strong>schutz erfordert auch einige Anforderungen an die<br />

Hardware, wie zwei verschiedene Modi, um zu entscheiden, ob der laufende Prozeß ein<br />

Betriebssystem- oder ein Nutzerprozeß ist und ein Mechanismus zum Umschalten vom<br />

Nutzermodus in den Supervisormodus und zurück.<br />

Zusammenfassung<br />

Die virtuelle <strong>Speicher</strong>technik wird vom Betriebssystem gesteuert und beruht auf dem Prinzip<br />

der Lokalität. Sie steuert automatisch die Ebenen Hauptspeicher und sekundärer <strong>Speicher</strong>, und<br />

läßt diese als eine Ebene erscheinen. Ihre Implementierung stellt Anforderungen sowohl an<br />

Hardware (z.B. MMU) als auch an Software (z.B. Seitenüberwacher). Die Implementierung<br />

ist zwar sehr komplex, aber es gibt bis heute noch keine Alternative für die Bewältigung des<br />

Problems der Fragmentierung des Hauptspeichers, des <strong>Speicher</strong>schutzes und dem des<br />

beschränkten Hauptspeichers. Der <strong>Speicher</strong>schutz wird durch die Verwendung von User-<br />

/Kernel-Bits, Schreibschutz-Bit und diversen Zugriffs-Bits in der Verwaltungseinheit der<br />

Seitentafel realisiert. Sie erlaubt effiziente und sichere Teilung des <strong>Speicher</strong>s für verschiedene<br />

Prozesse. Die Fragmentierung wird mit einer flexiblen Abbildung durch eine Seitentafel<br />

beseitigt. Einen größeren Adreßraum bekommt man dadurch, daß man die Ebene sekundärer<br />

<strong>Speicher</strong> mit einbezieht und automatisch verwaltet. Typische Werte für virtuellen <strong>Speicher</strong><br />

sind in Tabelle 7.1 zu sehen.<br />

Selbst wenn RAM immer günstiger und größer wird und man eigentlich genügend <strong>Speicher</strong><br />

auch für mehrere große Prozesse hat, ist die Implementierung des virtuellen <strong>Speicher</strong>s immer<br />

noch sinnvoll. Sie stellt ja nicht nur einen größeren <strong>Speicher</strong>bereich zur Verfügung, sondern<br />

bietet auch sonst noch einige Vorteile, wie <strong>Speicher</strong>schutz und flexiblere<br />

Hauptspeichernutzung. Deswegen ist eine Ablösung der virtuellen <strong>Speicher</strong>technik durch eine<br />

andere Technik auch noch nicht absehbar.<br />

Es gibt heute schon Betriebssysteme, die einen 64-Bit Adreßraum verwenden, wie das<br />

Betriebssytem Open VMS Alpha von DEC. Es benutzt 8 KB große Seiten und eine dreistufige<br />

Seitentafel, was einen virtuellen Adreßraum von 8 TB (1024 x 1024 x 1024 x 8KB) ergibt.<br />

Für die gesamte Abbildung in den <strong>Speicher</strong> werden dann, bei 8 Byte langen<br />

Seitentafelneinträgen, alleine insgesamt 8 GB (1024 x 1024 x 1024 x 8 Byte) für die<br />

Seitentafeln eines Prozesses benötigt. Das Betriebssystem ist vor allem für große


Datenbanksysteme geeignet. Einige Terabytes an virtuellen <strong>Speicher</strong> und mehrere Gigabytes<br />

an Hauptspeicher erlauben es, Datenbanken vollständig in den virtuellen <strong>Speicher</strong> zu laden,<br />

was viel Zeit bei Datenbankabfragen spart.<br />

Literatur<br />

1<br />

2<br />

3<br />

DAVID A. PATTERSON AND JOHN L. HENNESSY:<br />

Computer Organization & Design.<br />

2nd ed., Morgan-Kaufmann, 1997<br />

PAUL HERRMANN:<br />

Rechnerarchitektur.<br />

Vieweg, 1998<br />

DON ANDERSON AND TOM SHANLEY:<br />

Pentium Processor System Architecture.<br />

2nd ed., Addison-Wesley, 1995

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!