Remove ads
Zuordnung logischer Speicherblöcke z. B. eines Anwendungsprogramms zu physischen Speicherbereichen eines Computers Aus Wikipedia, der freien Enzyklopädie
Als Paging (vgl. engl. page „Speicherseite“) bezeichnet man die Methode der Speicherverwaltung per Seitenadressierung durch Betriebssysteme. Nur selten wird die deutsche Bezeichnung Kachelverwaltung verwendet.[1]
Das Paging ermöglicht eine virtuelle Speicherverwaltung. Der virtuelle Speicher bezeichnet den vom tatsächlich vorhandenen physischen Arbeitsspeicher unabhängigen Adressraum, der einem Prozess vom Betriebssystem zur Verfügung gestellt wird. Da meist mehr virtuelle Adressen existieren, als im physischen Arbeitsspeicher umsetzbar sind, werden einige Speicherbereiche vorübergehend auf die Festplatte ausgelagert.
Beim Paging wird der virtuelle Adressraum in gleich große Stücke unterteilt, die man als Seiten (engl. pages) bezeichnet. Auch der physische Adressraum ist derart unterteilt. Die entsprechenden Einheiten im physischen Speicher nennt man Seitenrahmen oder auch Kacheln (engl. page frames). Die Seiten werden in der sogenannten Seitentabelle (engl. page table) verwaltet, die Informationen darüber enthält, wo für eine (virtuelle) Seite der entsprechende (reale) Seitenrahmen im Arbeitsspeicher tatsächlich zu finden ist, sowie meistens Zusatzinformationen zum Beispiel zu Gültigkeit, Schreibrechten oder ob (sowie evtl. wohin) die Seite ausgelagert wurde.
Wenn ein Prozess eine virtuelle Adresse anspricht, die keiner physischen Arbeitsspeicher-Adresse zugeordnet ist, wird ein Systemaufruf ausgelöst. Dieser Aufruf wird Seitenfehler (engl. page fault) genannt. Als unmittelbare Folge des Seitenfehlers kommt es zu einer synchronen Prozessunterbrechung (Trap). Das Betriebssystem prüft dann, ob ein zugehöriger Seitenrahmen existiert und gerade ausgelagert ist – dann wählt es einen wenig benutzten Seitenrahmen aus, schreibt dessen Inhalt zurück auf die Festplatte, lädt den benötigten Seitenrahmen in den frei gewordenen Arbeitsspeicherbereich, ändert die Zuordnungstabelle und setzt den unterbrochenen Prozess mit dem fehlgeschlagenen Befehl fort.
Existiert zu der angeforderten virtuellen Adresse kein ausgelagerter Seitenrahmen, so kann das Betriebssystem entweder einen (ggf. zuvor „freigeschaufelten“) leeren realen Seitenrahmen zuordnen und den Prozess fortsetzen, oder den Prozess abbrechen unter dem Hinweis „Seitenfehler“. Aktuell verbreitete Betriebssysteme brechen einen Prozess in diesem Fall ab.
Der physische Adressraum ist durch den tatsächlich verfügbaren Arbeitsspeicher (Hauptspeicher) gegeben. Eine physische Adresse ist eine reale Adresse einer Speicherzelle im Arbeitsspeicher. Meistens verwenden Prozesse jedoch nicht mehr physische, sondern nur noch virtuelle (logische) Adressen. Das Prinzip der virtuellen Speicherverwaltung ermöglicht es, dass alle aktiven Prozesse mehr Speicherplatz belegen dürfen, als tatsächlich im physischen Adressraum zur Verfügung steht. Die virtuellen Adressen bilden den virtuellen Adressraum. Diese gehen nun nicht direkt an den Speicherbus, sondern an die Memory Management Unit (MMU, dt. Speicherverwaltungseinheit), welche die virtuellen Adressen auf die physischen Adressen abbildet.[2]
Aus der Sicht des Programmierers, der mit virtuellen Adressen arbeitet, erscheint der Adressraum (fast) unbegrenzt. Er braucht keine Rücksicht darauf zu nehmen, ob diese Adressen im real vorhandenen physischen Arbeitsspeicher wirklich existieren. Das Betriebssystem löst diese Aufgabe mit der vorübergehenden Auslagerung von Speicherbereichen auf einen Massenspeicher, meistens die Festplatte.[3] Bei der Speicherverwaltung werden also Daten vom Arbeitsspeicher auf die Festplatte ein- und ausgelagert.
Häufig verfügt ein System über sehr viel mehr virtuellen als physischen Speicher. Konkret legt das installierte RAM fest, wie groß der physische Speicher ist, während der virtuelle Adressraum von der Architektur des Befehlssatzes abhängt. Mit einem 32-Bit-Prozessor kann man maximal Byte (also 4 GiB) Speicher adressieren, mit einem 64-Bit-System Byte (16 EiB), auch wenn beispielsweise nur 512 MiB RAM tatsächlich installiert sind.[2]
Das Konzept der virtuellen Speicherverwaltung ist meist Basis für Multitasking, da so jeder Task einen eigenen Adressraum besitzen kann, was die Abschirmung der Tasks voneinander unterstützt; zusätzlich ist die Größe des Task-Adressraums nicht mehr abhängig davon, wie viel Arbeitsspeicher andere Tasks belegen.[2]
Zur Organisation des virtuellen Speichers gibt es einerseits den segmentorientierten Ansatz (siehe Segmentierung), bei dem der Speicher in Einheiten unterschiedlicher Größen aufgeteilt ist, und andererseits den seitenorientierten Ansatz (Paging), bei dem alle Speichereinheiten gleich lang sind.
Beim Paging wird der virtuelle Adressraum in gleich große Stücke unterteilt, die man als Seiten (engl. pages) bezeichnet. Auch der physische Adressraum ist derart unterteilt. Die entsprechenden Einheiten im physischen Speicher nennt man Seitenrahmen oder auch Kacheln (engl. page frames). Seiten und Seitenrahmen sind in der Regel gleich groß, beispielsweise 4 KiB.[4]
Beispiel: Die physische Größe des Arbeitsspeichers sei 64 KiB. Ein Programm benötigt insgesamt 200 KiB Speicher. Um das größere Programm trotzdem auf dem kleineren Arbeitsspeicher ausführen zu können, kann man den Adressraum in Seiten (Pages) aufteilen, beispielsweise vier Seiten zu 64 KiB, wobei dann die letzte Seite nur teilweise gefüllt ist. Es befindet sich dann jeweils eine der vier Seiten im physischen Arbeitsspeicher, die anderen drei sind auf die Festplatte ausgelagert.[3]
Der Teil der Festplatte, der für die ausgelagerten Seiten verwendet wird, wird Paging-Area oder Schattenspeicher genannt. Zum Ein- und Auslagern der Seiten existieren viele verschiedene Strategien. Grundsätzlich wird immer versucht, die Seiten im Arbeitsspeicher zu halten, die auch in naher Zukunft verwendet werden, um möglichst selten ein Paging durchzuführen.[5]
Solange die Speicherzugriffe Seiten betreffen, die im Arbeitsspeicher liegen, arbeitet das System ganz normal. Wird aber eine Seite im ausgelagerten Speicher angesprochen, muss die angeforderte Seite eingelagert werden (und unter Umständen eine andere Seite ausgelagert werden). Außerdem muss eine Adressabbildung aktiviert werden. Das ganze Verfahren heißt Seitenauslagerung oder Paging.[3]
Im Multiprogramming-Betrieb stellt der Memory-Manager jedem Prozess einen eigenen virtuellen Adressraum zur Verfügung, d. h. eine Menge von Adressen, die ein Prozess zur Adressierung des Speichers benutzen kann.[6] Der virtuelle Adressraum eines Prozesses wird nun beim Paging in Einheiten aufgebrochen, die sogenannten Seiten. Diese werden in der sogenannten Seitentabelle (page table) verwaltet, die Informationen darüber enthält, wo für eine Seite die entsprechenden Seitenrahmen im Arbeitsspeicher tatsächlich zu finden sind.[7] Mathematisch kann die Tabelle als eine Funktion aufgefasst werden, die die virtuelle Seitennummer als Argument nimmt und die Seitenrahmennummer (Page-Frame-Nummer) als Ergebnis liefert. Dadurch kann eine virtuelle Adresse auf eine physische Adresse abgebildet werden.[8]
Eine virtuelle Adresse wird in zwei Teile zerlegt: Eine virtuelle Seitennummer (höherwertige Bits) und einen Offset (niederwertige Bits). Die virtuelle Seitennummer wird als Index für den Eintrag in der Seitentabelle benutzt. Der Offset stellt den relativen Abstand einer Adresse zu einer Basisadresse dar. Er ist also die Distanz, die die genaue Byteadresse innerhalb einer Seite angibt. Mit Hilfe der virtuellen Seitennummer als Index wird in der Seitentabelle der zugehörige Eintrag ausfindig gemacht. Dieser enthält einen Verweis auf den Seitenrahmen (Page-Frame). Die Seitenrahmennummer wird zur physischen Adresse ergänzt und zusammen mit der Distanz (Offset) erhält man die physische Adresse. Die Größe des Offsets sollte also so gewählt werden, dass damit jede Adresse innerhalb einer Seite angesprochen werden kann.[9]
Die folgende Grafik veranschaulicht, wie aus einer virtuellen Adresse eine physische Adresse (hier: Reale Adresse) berechnet wird:
Die virtuelle Adresse besteht aus zwei Binärzahlen, die n-bit-lange Seitennummer und der m-bit-lange Offset. Der höherwertige Teil der physischen Adresse (hier: Basisadresse der realen Seite) wird der Seitentabelle entnommen, mit der Seitennummer als Index. Wird dieser mit dem Offset konkateniert, so ergibt sich eine neue Zahl, die genau die physische Speicheradresse ist. Derartige Berechnungen werden von der Memory Management Unit durchgeführt.
Die Adressen auf der Festplatte, an denen die ausgelagerten Seiten liegen, werden nicht in der Seitentabelle gespeichert. Diese enthält nur Informationen, die die Hardware zur Umrechnung einer virtuellen Adresse in eine physische benötigt. Bei der Behandlung von Seitenfehlern wird auf eigene Tabellen im Betriebssystem zurückgegriffen.[10]
Über die Seitennummer als Index kann ein Eintrag in der Seitentabelle adressiert werden. Der genaue Aufbau eines solchen Eintrages ist stark maschinenabhängig. Die darin enthaltene Information ist jedoch von Maschine zu Maschine etwa gleich. Nach Andrew S. Tanenbaum (2009) sieht ein typischer Seitentabelleneintrag folgendermaßen aus:[8]
Die einzelnen Einträge haben dabei die folgenden Bedeutungen:[11]
Wenn ein Prozess eine Adresse anspricht, die nicht im Arbeitsspeicher geladen ist, erzeugt die MMU einen sogenannten Seitenfehler (engl. page fault), dessen Behandlung vom Betriebssystem übernommen wird. Für einen Seitenfehler gibt es zwei generelle Ursachen:
Als unmittelbare Folge eines Seitenfehlers kommt es zu einer synchronen Prozessunterbrechung (Trap): Es wird ein sogenannter Pagefault-Interrupt ausgelöst. Das Betriebssystem springt im Kernelmodus auf eine spezielle Unterbrechungsroutine zur Bearbeitung des Seitenfehlers und versucht unter Beachtung der Seitenersetzungsstrategie und der Vergabestrategie die Seite in einen Seitenrahmen zu laden. Anschließend erhält der unterbrochene Prozess nach Möglichkeit entweder sofort oder später wieder den Prozessor (siehe dazu Prozesszustände). Insbesondere werden die folgenden Schritte durch das Betriebssystem ausgeführt:[13]
Um einen freien Seitenrahmen zu finden, kann beispielsweise eine Freelist verwaltet werden. Dafür eignet sich ein Bitvektor, der für jeden Seitenrahmen ein Bit enthält. Ist das Bit gesetzt, so wird dieser benutzt, andernfalls ist er frei und kann belegt werden. Sobald ein Seitenrahmen belegt oder freigegeben wird, muss natürlich die Freelist entsprechend angepasst werden.[14]
Translation Lookaside Buffer (Adressumsetzpuffer, kurz: TLB) werden eingesetzt, um die Übersetzung der virtuellen in die physischen Adressen zu beschleunigen.
Würde ausschließlich die Seitentabelle im Arbeitsspeicher gehalten, würde die Ausführungsgeschwindigkeit deutlich verringert. Beispielsweise ist für einen 1-Byte-Befehl, der ein Register in ein anderes kopiert, ohne Paging nur ein Speicherzugriff nötig, um den Befehl aus dem Speicher zu holen. Mit Paging ist mindestens ein zusätzlicher Speicherzugriff auf die Seitentabelle erforderlich. Wenn also nun zwei Speicherzugriffe pro Befehl erforderlich werden, würde die Leistung der CPU in etwa halbiert.
Deshalb werden die zuletzt ermittelten Werte für die Adresse der physischen Speicherseite im Translation Lookaside Buffer (TLB) gecacht, wodurch erneute Zugriffe auf Adressen in dieser Seite nicht aufwändig neu ermittelt werden müssen, sondern aus dieser Liste entnommen werden können. Der TLB kann eine begrenzte Menge dieser Referenzen halten und kann dadurch die Ausführung von Speicherzugriffen deutlich beschleunigen. Dies wird über assoziative Ordnungsregister realisiert, die parallele Zugriffe erlauben. Der TLB ist normalerweise ein Teil der MMU. Die Felder des TLB sind normalerweise eins zu eins aus der Seitentabelle entnommen, mit Ausnahme der virtuellen Seitennummer, die in der Seitentabelle nicht benötigt wird. Ein weiteres Feld gibt zudem an, ob der Eintrag momentan benutzt wird.[15]
Die Anzahl der Felder eines TLB hängt von der Rechnerarchitektur ab und liegt häufig zwischen 8 und 256. IA-64-Architekturen verfügen beispielsweise über 128 Einträge im TLB. Aufgrund der hohen Lokalität vieler Programme, kann bereits bei acht Einträgen eine beachtliche Leistungssteigerung erzielt werden.[16]
Wenn eine virtuelle Adresse zur Übersetzung an die MMU geschickt wird, überprüft also diese zuerst, ob ein entsprechender Eintrag im TLB vorhanden ist, indem sie die virtuelle Seitennummer mit allen Einträgen gleichzeitig (parallel) vergleicht. Wird ein passender Eintrag gefunden, kann die Seitennummer aus dem TLB verwendet werden. Andernfalls tritt ein TLB-Fehler auf. Die MMU holt entsprechend den Eintrag aus der Seitentabelle und schreibt ihn zudem in den TLB.
Die Größe der Seitenrahmen (page frames) hat einen erheblichen Einfluss auf die Speicherausnutzung. Für große Seiten erhält man mehr Treffer pro Seitenaufruf, d. h., es sind weniger Einlagerungen nötig. Zudem reicht dann eine kleinere Seitentabelle aus. Allerdings können sich dann auch weniger Seiten gleichzeitig im Arbeitsspeicher befinden und es gibt eine größere interne Fragmentierung, die dadurch entsteht, dass einem Prozess insgesamt ein größerer Speicherbereich zugewiesen ist, als er eigentlich benötigt. Konkret besteht die interne Fragmentierung aus einem Teil der letzten Seite eines Prozesses. Sind die Seitenrahmen dagegen zu klein, benötigt man sehr lange Seitentabellen. Die optimale Seitengröße stellt einen Ausgleich zwischen diesen Effekten dar.[17][18]
Eine standardmäßige Seitengröße wird normalerweise durch die Hardware vorgegeben. Die Seitengröße neigt dazu, mit dem Speicher zu wachsen, aber nicht linear. Wenn sich der Speicher vervierfacht, wird die Seitengröße meistens nicht einmal verdoppelt.[19]
Der Pentium 4 und alle anderen IA-32-Prozessoren stellen ein Paging mit einer fixen Seitengröße von 4 KiB zur Verfügung. Einige Prozessoren unterstützen auch mehrere Seitengrößen, die man teils gleichzeitig nutzen kann. Ab dem Pentium Pro kann die Seitengröße wahlweise auf 4 KiB oder 2 MiB mit PAE bzw. 4 MiB ohne PAE eingestellt werden.[20] Bei der AMD64-Architektur werden physische Seitengrößen von 4 KiB, 2 MiB, 4 MiB und 1 GiB unterstützt.[21] Durch die Nutzung verschiedener Seitengrößen (page sizes) kann ein Systeme die jeweiligen Vorteile besser nutzen, beispielsweise für Teile des Betriebssystems und den Grafikspeicher große Seitengröße (Large Pages) verwenden, z. B. 8 MiB.[22]
Auch wenn die Hardware gewisse Seitengrößen vorgibt, kann das Betriebssystem diese beeinflussen. Wenn die Hardware beispielsweise für 4-KiB-Seiten entworfen wurde, kann das Betriebssystem die Seitenrahmen 0 und 1, 2 und 3, 4 und 5 usw. als 8-KiB-Seiten behandeln, indem es bei einem Seitenfehler (page fault) gleich zwei aufeinander folgende Seitenrahmen nachlädt.[23]
Während die kleinere Seitengröße meist von der Architektur (teilweise aber auch dem Betriebssystem) vorgegeben ist, sehen verschiedene Systeme zusätzlich eine meist definierte große Seitengröße vor. Unter BSD-Unix heißen diese super pages, unter Windows (genauer: Windows NT) large pages und unter Linux huge pages. Die folgende Tabelle zeigt Seitengrößen unter Windows in Abhängigkeit von der Prozessorarchitektur:[24][25][26]
Da die Anzahl der Einträge einer (einstufigen) Seitentabelle von der Größe des virtuellen Adressraums und der gewählten Seitengröße abhängt, ergibt sich ein Problem, wenn der virtuelle Adressraum zu groß und/oder die gewählte Seitengröße zu klein wird. Bei einem 64-Bit-Computer mit einem Adressraum von Byte und 4 Kibibyte () großen Seiten hätte die Seitentabelle Einträge. Mit beispielsweise 8 Byte pro Eintrag (52 Bit für die Adressierung, 7 Statusbits gemäß obigem Beispiel) wäre die Seitentabelle dann über 33 Millionen Gibibyte (32 Pebibyte) groß, im Gegensatz zu einer Größe von nur 4 Mebibyte bei gleicher Seitengröße auf einem 32-Bit-Computer mit beispielsweise 4-Byte-Seitentabelleneinträgen (20 Bit für die Adressierung, 7 Statusbits gemäß demselben obigen Beispiel). Für virtuelle 64-Bit-Adressräume mit Paging sind also andere Lösungen nötig.[27] Deshalb wurden die Konzepte der mehrstufigen Seitentabelle und der invertierten Seitentabelle entwickelt.
Die Adressumsetzung mit Hilfe einer k-stufigen Seitentabelle geschieht durch Aufteilung einer virtuellen Adresse in k*n höherwertige Bits als Seitentabellenverweise und m niederwertige Bits als Offset. Mit dem k-ten Verweis in der virtuellen Adresse wird aus der k-ten Seitentabelle die Basisadresse der Seitentabelle der Stufe k+1 ausgelesen. Die letzte Stufe enthält dann den tatsächlichen Verweis auf die reale Basisadresse. Die aus der letzten Stufe der Seitentabellen ausgelesene Basisadresse der realen Speicherseite zusammen mit dem unveränderten Offset ergeben die reale Adresse.
Der Vorteil bei diesem Ansatz gegenüber der einstufigen Seitentabelle ist der, dass nicht immer alle Seitentabellen im Speicher gehalten werden müssen. Besonders die nicht benötigten Tabellen sollten nicht nutzlos im Speicher gehalten werden. Die Seitentabellen selbst können also auch ausgelagert werden, sie unterliegen ebenfalls dem Paging.[28]
Für die IA-32-Prozessoren entschied man sich beispielsweise für eine zweistufige Seitenverwaltung, bei der ein zentrales Seitenverzeichnis (page directory) auf bis zu 1024 Seitentabellen (page tables) verweist. Die virtuelle Adresse wurde für die Umsetzung in drei Teile aufgeteilt:
Bei x64-Windows ist die Seitentabelle sogar vierstufig. Es wird eine 48 Bit breite virtuelle Adresse in 4 Indices zu je 9 Bit und einen Offset zu 12 Bit eingeteilt.[30]
Bei der Methode der invertierten Seitentabelle wird in der Seitentabelle nicht mehr ein Eintrag pro virtueller Seite angelegt, sondern nur noch ein Eintrag für jeden physischen Seitenrahmen. Wenn der virtuelle Adressraum wesentlich größer als der physische Speicher ist, wird dadurch sehr viel Speicherplatz der Tabelle eingespart.
Jeder Eintrag in der Tabelle speichert das zugehörige Paar (Prozessnummer, Seitennummer). Der Zugriff auf die Seitentabelle erfordert nun jedoch einen Suchvorgang: Wenn ein Prozess mit der Prozessnummer n auf die virtuelle Seite p zugreifen will, muss die Hardware die gesamte Tabelle nach dem Eintrag (n,p) durchsuchen. Dies macht einen Speicherzugriff wesentlich aufwändiger. Abhilfe schafft das Vorschalten einer Hashtabelle mit den virtuellen Adressen als Hashwerten. Alle Seiten, die denselben Hashwert haben, werden verkettet.
Zusätzlich wird der Speicherzugriff durch einen Translation Lookaside Buffer (TLB) beschleunigt. Wenn alle häufig benutzten Seiten in den TLB passen, ist die Adressumrechnung gleich schnell wie mit herkömmlichen Methoden. Bei einem TLB-Fehler muss jedoch die invertierte Seitentabelle von der Software durchsucht werden.[31]
Beim sogenannten Demand Paging (Einlagern bei Bedarf) erfolgt eine Einlagerung nur auf Anforderung, also wenn die Daten tatsächlich benötigt werden. In der reinsten Form des Demand Paging startet ein Prozess mit keiner einzigen Seite im Arbeitsspeicher. Sobald die CPU den ersten Befehl laden will, gibt es einen Seitenfehler und das Betriebssystem lagert die entsprechende Seite ein. Es folgen weitere Seitenfehler, bis der Prozess die wichtigsten Seiten „zusammengetragen“ hat und mit relativ wenigen Seitenfehlern laufen kann.[32]
Beim sogenannten Prepaging können dagegen auch Seiten in den Hauptspeicher geholt werden, die noch nicht angefordert wurden. Es wird dabei die räumliche Lokalitätseigenschaft ausgenutzt. Diese besagt, dass nach einem Zugriff auf einen Adressbereich mit hoher Wahrscheinlichkeit der nächste Zugriff auf eine Adresse in unmittelbarer Nachbarschaft erfolgt.
Auch Kombinationen von Demand Paging und Prepaging werden in der Praxis eingesetzt: Man kann zum Beispiel beim Holen einer angeforderten Seite gleich die benachbarten Seiten oder sonstige Seiten nach einem bestimmten Algorithmus mit in den Hauptspeicher laden.[5]
Wenn in einem Rechnersystem zu viele Seitenfehler in zu kurzer Zeit auftreten, ist das System überwiegend mit dem Nachladen und Auslagern von Seiten beschäftigt. Die verfügbare Rechenleistung ist deutlich herabgesetzt. Dieser Zustand wird als Thrashing (engl. wörtlich: Dreschen) oder Seitenflattern bezeichnet.[33]
Thrashing tritt beispielsweise auf, wenn zu viele Prozesse im Speicher sind. Durch die zusätzliche Belastung mit Prozessen nimmt einerseits die verfügbare Seitenzahl pro Prozess im Arbeitsspeicher ab und andererseits die Zahl der Seitenaustauschaktivitäten zu. Prozesse laufen nicht mehr ab, ohne nach kurzer Zeit auf nicht vorhandene Seiten zu stoßen. Es können jedoch nur Seiten aus dem Speicher verdrängt werden, die kurz danach wieder benötigt werden. Ab einer gewissen Grenze wird die zur Verfügung stehende Rechenleistung nahezu vollständig darauf verwendet, Speicherinhalte ein- und auszulagern und nach rechenbereiten Prozessen zu suchen.[34]
Die Menge von Seiten, die ein Prozess zu einem bestimmten Zeitpunkt benutzt, wird als Arbeitsbereich (engl. working set) bezeichnet.[35] Liegt der gesamte Arbeitsbereich eines Prozesses im Arbeitsspeicher, läuft er mit sehr wenigen Seitenfehlern ab. Das Working-Set-Modell versucht deshalb die Seitenfehlerrate zu verringern, indem sich das Betriebssystem den Arbeitsbereich eines Prozesses merkt, wenn es ihn auslagert und dafür sorgt, dass er wieder eingelagert wird, bevor er erneut ausgeführt wird.[36]
Um Thrashing zu vermeiden, sollten die folgenden Punkte beachtet werden:
Entscheidend sind dabei folgende Größen:
Damit Thrashing vermieden wird, muss p(s) ≤ t/T sein. Der minimale Anteil w an Seiten, der sich im Arbeitsspeicher befinden muss (also der Arbeitsbereich), wird bestimmt durch die Gleichung
Da Speicherzugriffe meist lokal gehäuft auftreten, ist die Wahrscheinlichkeit sehr hoch, dass der nächste Programmschritt und das nächste benötigte Datenelement sich auf derselben Seite befinden wie der gerade verarbeitete Schritt und das gerade verarbeitete Element. Auf der anderen Seite ist das Verhältnis T/t typischerweise sehr groß: RAM ist ca. 100000-mal so schnell wie Festplattenspeicher.
Experimentelle Messungen und Berechnungen, die bereits in den 1960er Jahren durchgeführt wurden, ergeben unter diesen Bedingungen für w einen Wert von nicht wesentlich weniger als 0,5. Das bedeutet, dass der Auslagerungsspeicher kaum größer als der Arbeitsspeicher sein muss. In der Praxis wird z. B. unter UNIX-Betriebssystemen für die meisten Anwendungsfälle eine Größe des Auslagerungsspeichers vom Zwei- bis Dreifachen des Arbeitsspeichers empfohlen (abhängig davon, ob das jeweilige System den Auslagerungsspeicher zusätzlich zum Arbeitsspeicher oder den Arbeitsspeicher als echte Teilmenge des Auslagerungsspeichers verwaltet).[37]
Wenn ein Seitenfehler auftritt, muss unter Umständen eine Seite im Arbeitsspeicher verdrängt werden, um für die neue Seite Platz zu schaffen. Die Leistung eines Pagingsystems hängt wesentlich davon ab, welche Seiten im Arbeitsspeicher man beim Nachladen neuer Seiten verdrängt. Wenn man eine viel benutzte Seite verdrängt, dann erzeugt man Aufwand für zusätzliche Nachladevorgänge. Nach Möglichkeit sollten also Seiten ausgelagert werden, die nur selten benutzt werden.
Das Gebiet der Seitenersetzungsalgorithmen wurde sowohl theoretisch als auch experimentell intensiv erforscht. Die Problematik besteht darin, dass das Betriebssystem nicht wissen kann, wann auf welche Seite das nächste Mal zugegriffen wird.[38]
Diese Paging-Strategie lagert bevorzugt Seiten aus, die innerhalb eines Zeitintervalls nicht benutzt (referenziert) und nicht modifiziert wurden. Dazu werden die Seiten in regelmäßigen Abständen als ungelesen und unverändert markiert. Wenn eine Seite ausgelagert werden muss, wird geprüft, bei welchen Seiten sich diese Markierungen nicht geändert haben.
Das Betriebssystem führt mit Hilfe der beiden Statusbits Statistiken über die Benutzung von Seiten:
Das Betriebssystem setzt nun in regelmäßigen Abständen (z. B. bei jedem Timerinterrupt) die R-Bits auf 0. Dadurch ist das R-Bit nur bei den Seiten gesetzt, die in letzter Zeit gebraucht wurden. Bei einem Seitenfehler teilt das Betriebssystem die Seiten nach dem Zustand der R- und M-Bits in vier Kategorien ein, die mit entsprechender Priorität ausgelagert werden:
Die Leistung des NRU-Algorithmus ist zwar nicht optimal, aber in vielen Fällen ausreichend.[39]
Bei dieser Methode werden diejenigen Elemente, die zuerst gespeichert wurden, auch wieder zuerst aus dem Speicher genommen. Auf die Seitenersetzung übertragen bedeutet dies, dass jeweils die älteste Seite ersetzt wird. Das Betriebssystem führt eine Liste mit allen Seiten im Speicher, wobei am Eingang der jüngste und am Ende der älteste Eintrag steht. Bei einem Seitenfehler wird das Ende abgehängt und eine neue Seite am Eingang angehängt. Diese Strategie ist ineffizient, da die älteste Seite durchaus eine Seite mit sehr häufigen Zugriffen sein kann.[40]
Der Second-Chance-Algorithmus ist eine Verbesserung des First-In-First-Out-Algorithmus. Es soll dabei verhindert werden, dass die älteste Seite ausgelagert wird, obwohl sie häufig benutzt wird. Deshalb wird zunächst das R-Bit abgefragt. Es gibt nun zwei Fälle:
Der Second-Chance-Algorithmus ist allerdings ineffizient, da er ständig Seiten in der Liste verschiebt. Eine Verbesserung dazu stellt der Clock-Algorithmus dar: Die Seiten werden in einer ringförmigen Liste gehalten und ein Zeiger zeigt auf die älteste Seite, vergleichbar mit einem Uhrzeiger. Wenn nun das R-Bit 0 ist, wird die Seite ausgelagert (und die neue Seite an derselben Stelle eingelagert), ansonsten wird das R-Bit auf 0 gesetzt und der Zeiger rückt um eine Seite vor.[41]
Diese Strategie lagert diejenige Seite aus, deren letzte Referenzierung zeitlich am längsten zurückliegt. Man geht also von der Annahme aus, dass Seiten, die lange nicht genutzt wurden, auch in Zukunft nicht verwendet werden und Seiten, die in der jüngsten Vergangenheit genutzt wurden, auch in Zukunft häufig verwendet werden. Der LRU-Algorithmus ist zwar eine gute Annäherung an den optimalen Algorithmus, er ist allerdings nur ziemlich aufwändig zu realisieren. Es muss einiger Aufwand betrieben werden, um jeweils die am längsten unbenutzte Seite schnell im Zugriff zu haben.[42]
Eine Möglichkeit besteht darin, eine nach der zeitlichen Nutzung sortierte Liste zu führen. Bei jedem Zugriff wird dabei die aktuell genutzte Seite an den Listeneingang gehängt. Das Finden, Verschieben und Löschen einer Seite in der Liste sind jedoch sehr aufwändige Operationen.
Eine weitere Möglichkeit besteht darin, LRU mit Spezialhardware zu implementieren. Die LRU-Hardware führt beispielsweise für eine Maschine mit n Seitenrahmen eine -Matrix. Anfangs sind alle Einträge auf 0 gesetzt. Wird auf einen Seitenrahmen k zugegriffen, setzt die Hardware alle Bits der Zeile k auf 1 und dann alle Bits der Spalte k auf 0. Zu jedem Zeitpunkt ist dadurch die am längsten nicht benutzte Seite diejenige mit dem niedrigsten Binärwert in der entsprechenden Zeile der Matrix.[43]
Aufgrund des hohen Aufwands werden in der Praxis sogenannte Pseudo-LRU-Algorithmen vorgezogen, die das R- und das M-Bit benutzen. Dazu gehören auch der Second-Chance-Algorithmus und der Clock-Algorithmus.[44]
Der Working-Set-Algorithmus basiert auf der Idee, dass bei einem Seitenfehler eine Seite ausgelagert wird, die nicht mehr zum Arbeitsbereich eines Prozesses gehört. Dazu führt die Seitentabelle neben dem R-Bit noch zusätzlich einen Eintrag, der die (ungefähre) Zeit des letzten Zugriffs beinhaltet. Der Algorithmus funktioniert folgendermaßen:
Der Working-Set-Algorithmus hat den Nachteil, dass bei jedem Seitenfehler die gesamte Seitentabelle durchlaufen werden muss, bis ein passender Kandidat gefunden ist.[45]
Der WSClock-Algorithmus ist einerseits eine Verbesserung des Clock-Algorithmus, nutzt andererseits aber auch Informationen über den Arbeitsbereich.[46] Wie beim Clock-Algorithmus werden die Seiteneinträge in einer ringförmigen Datenstruktur gehalten. Jeder Eintrag enthält ein R-Bit, ein M-Bit und ein Feld für den Zeitpunkt des letzten Zugriffs (vergleichbar zum Working-Set-Algorithmus). Bei einem Seitenfehler wird wie beim Clock-Algorithmus zunächst die Seite untersucht, auf die der Zeiger zeigt. Entscheidend sind die folgenden Fälle:
Wenn ein Zeiger die gesamte Liste einmal durchlaufen hat, gibt es folgende Fälle:
Wegen seiner guten Leistung und einfachen Implementierung ist der WSClock-Algorithmus in realen Systemen weit verbreitet.[47]
Die Adresslänge in diesem Beispiel sei 16 Bit, wobei die oberen 8 Bit die Seitennummer und die unteren 8 Bit der Offset sind. (Die Adresse eines Bytes ergibt sich also = Seitenrahmen * 256 + Offset.)
Eintrag | Gültig | Seitenrahmen |
---|---|---|
0 | Nein | – |
1 | Ja | 0x17 |
2 | Ja | 0x20 |
3 | Ja | 0x08 |
4 | Nein | – |
5 | Ja | 0x10 |
Zu übersetzende Adressen:
virtuelle Adresse | physische Adresse | Bemerkung |
---|---|---|
0x083A | ungültig | da die Seitentabelle nur Einträge bis Seite 5 enthält. |
0x01FF | 0x17FF | Seite 0x01 befindet sich in Seitenrahmen 0x17, also werden die oberen 8 bit der virtuellen Adresse durch 0x17 ersetzt |
0x0505 | 0x1005 | Seite 0x05 befindet sich in Seitenrahmen 0x10, also werden die oberen 8 bit der virtuellen Adresse durch 0x10 ersetzt |
0x043A | ungültig | da die Seite 0x04 als ungültig markiert wurde. |
Die meisten Architekturen verwenden ein mehrstufiges Paging, um die Seitentabellen kleinzuhalten. Die IA32-Architektur verwendete ursprünglich ein zweistufiges Paging. Die 32 Bit der linearen Adresse werden hierbei wie folgt aufgeteilt:
Bits | Zuordnung |
---|---|
31 … 22 | Index im Seitenverzeichnis (engl. page directory, kurz: PD) |
21 … 12 | Index in der Seitentabelle (engl. page table, kurz: PT) |
11 … 0 | Offset in der Speicherseite |
Das Seitenverzeichnis und jede Seitentabelle bestehen aus 1024 Einträgen zu je 4 Byte und belegen somit jeweils genau eine Speicherseite. Jeder Eintrag hat folgenden Aufbau:
Bits: | 31 … 12 | 11 … 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Inhalt: | Bit 31…12 der Basisadresse | ign. | G | PS | D | A | PCD | PWT | U/S | R/W | P |
Zur Optimierung großer, zusammenhängender Speicherbereiche (z. B. Framebuffer für Grafikkarten usw.) und um den Verwaltungsaufwand im Speichermanagement des Betriebssystems zu verringern, unterstützen CPUs ab dem Pentium (offiziell dokumentiert ab Pentium Pro) außerdem 4 MiB große Seiten. Dieses Feature wird Page-Size Extension (PSE) genannt. Hierbei markiert ein spezielles Bit im zugehörigen Seitenverzeichnis-Eintrag, dass die zweite Stufe im Paging für diesen Adressbereich umgangen werden soll. Damit geben die Bits 21 bis 0 der logischen Adresse direkt den Offset in der 4 MiB großen Speicherseite an.
Um die Page-Size Extension zu aktivieren, muss das Betriebssystem das Bit 4 im Steuerregister CR4 setzen.[48]
Da die 4-MiB-Seiten nur auf „glatten“ Adressen beginnen dürfen, müssen die Bits 12 bis 20 im Seitenverzeichniseintrag stets 0 sein. Dies wurde mit der PSE-36-Erweiterung abgeschafft, indem diese Bits eine neue Bedeutung bekamen:
Bits: | 31 … 22 | 21 | 20 … 17 | 16 … 13 | 12 | 11 … 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
PSE (ab Pentium): | Bit 31…22 der Basisadresse | 0 | PAT | ign. | G | PS | D | A | PCD | PWT | U/S | R/W | P | |||||||||||||||||||
PSE-36 (ab Pentium II Xeon) | Bit 31…22 der Basisadresse | 0 | Bit 35…32 | PAT | ign. | G | PS | D | A | PCD | PWT | U/S | R/W | P | ||||||||||||||||||
PSE-36 (ab AMD K8) | Bit 31…22 der Basisadresse | 0 | Bit 39…32 | PAT | ign. | G | PS | D | A | PCD | PWT | U/S | R/W | P |
Die PSE-36-Erweiterung ermöglichte es, ohne großen Änderungsaufwand am Betriebssystemkern, auf mehr als 4 GiB physischen Hauptspeicher zugreifen zu können. Allerdings ist Hauptspeicher jenseits der 4-GiB-Grenze nur über 4-MiB-Seiten ansprechbar.
PSE-36 wurde nur von Windows NT 4.0 verwendet. 32-Bit-Versionen von Windows nach NT 4.0 und Linux setzen ausschließlich auf die neuere Physical-Address Extension (PAE). Wenn PSE gemeinsam mit PAE aktiviert ist, sind die Speicherseiten nicht 4, sondern nur 2 MiB groß.[49]
Ab dem Pentium Pro ist es möglich, bis zu 236 Bytes (= 64 GiB) physischen Speicher zu adressieren. Diese Technik wird Physical-Address Extension genannt. Dafür wird das Paging um eine dritte Stufe erweitert. Die obersten beiden Bits der linearen Adresse wählen nun einen aus 4 Einträgen der so genannten page directory pointer table (kurz: PDPT) aus.
Die Einträge in den Tabellen wurden auf 8 Bytes erweitert, jede der Tabellen enthält allerdings nur noch 512 Einträge, so dass die Gesamtgröße der Tabelle wieder bei 4 KiB liegt:
Bits: | 63 | 62 … 52 | 51 … 32 | |||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Inhalt: | NX | reserved | Bit 51…32 der Basisadresse | |||||||||||||||||||||||||||||
Bits: | 31 … 12 | 11 … 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||||||||||||||||||||
Inhalt: | Bit 31…12 der Basisadresse | ign. | G | PAT | D | A | PCD | PWT | U/S | R/W | P |
Auch mit PAE ist es möglich, die letzte Adressübersetzungsstufe des Pagings zu deaktivieren. Die Bits 20 bis 0 der logischen Adresse bilden dann direkt den Offset einer 2 MiB großen Speicherseite.
Bits | Zuordnung | |
---|---|---|
4 KiB Page | 2 MiB Page | |
31 … 30 | Index in der PDPT | |
29 … 21 | Index im Seitenverzeichnis (engl. page directory, kurz: PD) | |
20 … 12 | Index in der Seitentabelle (engl. page table, kurz: PT) | Offset in der Speicherseite |
11 … 0 | Offset in der Speicherseite |
Mit der Einführung des 64-Bit-Modus beim AMD Athlon 64 wurde dieses Prinzip noch einmal angewendet. Das Paging wurde um eine vierte Stufe erweitert (Page Map Level 4, kurz PML4) und die PDPT wurde von 4 auf 512 Einträge vergrößert, so dass sie genauso groß wie die nachfolgenden Seitentabellen ist.
Neben den bereits im 32-Bit-Modus verfügbaren 4 KiB und 2 MiB großen Seiten sind im 64-Bit-Modus auch 1 GiB große Seiten möglich. Hierbei verweisen die unteren 22 Bits eines Eintrags in der Page-Directory-Pointer Table direkt auf die Startadresse einer 1-GiB-Seite:
Bits | Zuordnung | ||
---|---|---|---|
4 KiB Page | 2 MiB Page | 1 GiB Page | |
63 … 48 | Kopie von Bit 47, als Vorzeichenerweiterung | ||
47 … 39 | Index in der PML4 table (engl. page mapping layer 4) | ||
38 … 30 | Index in der PDPT | ||
29 … 21 | Index im Seitenverzeichnis (engl. page directory, kurz: PD) | 30-Bit-Offset | |
20 … 12 | Seitentabelle (engl. page table, kurz: PT) | 21-Bit-Offset | |
11 … 0 | 12-Bit-Offset in der Speicherseite |
Eine nochmalige Erweiterung[50] erfuhr das Konzept durch eine fünfte Stufe, die den Adressbereich noch einmal um 9 bit und damit auf 128 PiB erweitert. Die neue Tabelle wird als PML5 table bezeichnet, ist analog zur PML4 aufgebaut und enthält ebenso 512 Einträge. Um diesen Modus nutzen zu können, muss die Software zunächst mit einem neuen Flag feststellen, ob 5-Level-Paging unterstützt wird, oder ob nur 4-Level-Paging möglich ist.
Bits | Zuordnung | ||
---|---|---|---|
4 KiB Page | 2 MiB Page | 1 GiB Page | |
63 … 57 | Kopie von Bit 56, als Vorzeichenerweiterung | ||
56 … 48 | Index in der PML5 table (engl. page mapping layer 5) | ||
47 … 39 | Index in der PML4 table (engl. page mapping layer 4) | ||
38 … 30 | Index in der PDPT | ||
29 … 21 | Index im Seitenverzeichnis (engl. page directory, kurz: PD) | 30-Bit-Offset | |
20 … 12 | Seitentabelle (engl. page table, kurz: PT) | 21-Bit-Offset | |
11 … 0 | 12-Bit-Offset in der Speicherseite |
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.