Teil 4: Speicherverwaltung
Teil 4: Speicherverwaltung Teil 4: Speicherverwaltung
1 / 49 Vorlesung Betriebssysteme II Thema 4: Hauptspeicherverwaltung Robert Baumgartl 24. 04. 2012
- Seite 2 und 3: 2 / 49 Freispeicherverwaltung Motiv
- Seite 4 und 5: Bitmaps 4 / 49 ◮ Anforderung wird
- Seite 6 und 7: Freispeicherliste 6 / 49 ◮ Idee:
- Seite 8 und 9: 8 / 49 Freispeicherliste Suchstrate
- Seite 10 und 11: 10 / 49 Freispeicherliste Techniken
- Seite 12 und 13: 12 / 49 Getrennte Freispeicherliste
- Seite 14 und 15: 14 / 49 Buddy-Verfahren Idee: Syste
- Seite 16 und 17: 16 / 49 Virtueller Speicher Motivat
- Seite 18 und 19: 18 / 49 Virtueller Speicher Seiten
- Seite 20 und 21: Seitentabelleneintrag (Page Table E
- Seite 22 und 23: 22 / 49 Größe der Seitentabelle L
- Seite 24 und 25: Demand Paging 24 / 49 Idee: Benöti
- Seite 26 und 27: 26 / 49 Einlagerungsstrategien ◮
- Seite 28 und 29: 28 / 49 Seitenaustauschverfahren Op
- Seite 30 und 31: Seitenaustauschverfahren Not Recent
- Seite 32 und 33: Seitenaustauschverfahren NFU; Aging
- Seite 34 und 35: 34 / 49 Konzept der Arbeitsmenge (W
- Seite 36 und 37: Konzept der Arbeitsmenge (Working S
- Seite 38 und 39: 38 / 49 Abhängigkeit der Größe d
- Seite 40 und 41: Beladys Anomalie Vergrößerung von
- Seite 42 und 43: 42 / 49 Weitere Aspekte zur Seitene
- Seite 44 und 45: Speicherabbild eines Prozesses 44 /
- Seite 46 und 47: 46 / 49 Stackanforderung mittels al
- Seite 48 und 49: 48 / 49 Memory-mapped Files aka ‘
1 / 49<br />
Vorlesung Betriebssysteme II<br />
Thema 4: Hauptspeicherverwaltung<br />
Robert Baumgartl<br />
24. 04. 2012
2 / 49<br />
Freispeicherverwaltung<br />
Motivation<br />
Applikationen und das Betriebssystem selbst fordern zur<br />
Laufzeit Speicher an (und geben diesen später wieder zurück).<br />
→ Notwendigkeit der Verwaltung<br />
◮ notwendig, zur Laufzeit Speicher an Anfordernde<br />
(Applikationen, BS) auszureichen und wieder<br />
entgegenzunehmen<br />
◮ Schnittstelle: Menge an Funktionen, die Speicher<br />
anfordern und diesen wieder zurückgeben
Freispeicherverwaltung<br />
Probleme<br />
3 / 49<br />
◮ Fragmentierung:<br />
intern – Verlust durch feste Segmentgröße<br />
(„Verschnitt“)<br />
extern – Verlust durch inkohärente Speicherung<br />
(„Verstreuung“) → Kompensation durch<br />
Kompaktifizierung<br />
Table ∼ – Verlust durch Speicherbedarf der<br />
Verwaltungsstrukturen<br />
◮ Laufzeitkomplexität<br />
◮ der Suche nach freiem Segment<br />
◮ der Rückgabe des Segments (Wiedereinordnung)<br />
Zwei grundlegende Management-Techniken:<br />
1. Bitmaps<br />
2. Listen
Bitmaps<br />
4 / 49<br />
◮ Anforderung wird auf einen oder mehrere Blöcke einer<br />
fixen Größe abgebildet<br />
◮ „Karte“ des Hauptspeichers<br />
◮ Blöcke (allocation units) einheitlicher Größe<br />
◮ pro Block ein Bit:<br />
◮ = 0 → Block frei<br />
◮ = 1 → Block belegt<br />
belegt frei belegt belegt frei belegt belegt<br />
A B C D E<br />
frei<br />
n<br />
Allokations−<br />
einheit<br />
11111000<br />
11111111<br />
11001111<br />
11111000<br />
Bitmap
5 / 49<br />
Bitmaps<br />
Blockungsfaktor<br />
◮ Parameter: Blockungsfaktor n, beeinflusst:<br />
◮ Speicherbedarf für die Bitmap<br />
◮ interne Fragmentierung<br />
◮ Gefahr der externen Fragmentierung<br />
◮ fixe Größe der Verwaltungsstruktur<br />
◮ keine weiteren Verwaltungsinformationen in Bitmap<br />
speicherbar
Freispeicherliste<br />
6 / 49<br />
◮ Idee: Suche nach einem “‘passenden”’ freien Segment<br />
◮ ggf. Abtrennen des nicht benötigten Restes<br />
◮ d.h. , es werden stets exakt passende Segmente<br />
ausgegeben (→ keine interne Fragmentierung)<br />
◮ pro Segment ein Element einer verkettete Liste (einfach,<br />
doppelt, Ring), enthält:<br />
◮ Anfangsaddresse<br />
◮ Länge<br />
◮ belegt/frei-Information<br />
◮ Zeiger auf Nachfolge-Element<br />
◮ weitere Informationen, z. B. Eigentümer<br />
Start<br />
A 0 5 5 3 B 8 6 C 14 4<br />
18 2 D 20 6 E 26 3 29 3
Blöcke mit integrierten Headern<br />
7 / 49<br />
Variante: Header ist in Blöcke integriert (belegt/frei-Bit, Länge,<br />
evntl. Zeiger auf NF)<br />
Header<br />
0<br />
Länge<br />
Länge<br />
Länge<br />
1 0 1 1<br />
Länge<br />
Länge<br />
...
8 / 49<br />
Freispeicherliste<br />
Suchstrategien<br />
Suchoperation bei Forderung eines Segmentes der Größe m:<br />
First Fit<br />
◮ Durchsuchen der Liste beginnend von Start<br />
◮ erstes freies Segment ≥ m wird genutzt<br />
◮ ggf. Abtrennen des Überschusses (<strong>Teil</strong>ung des Segments;<br />
1 freies → 1 belegtes + 1 freies)<br />
◮ Tendenz: anfangs belegte Segmente, später mehr freie<br />
Segmente<br />
Next Fit<br />
◮ Start der Suche an letzer Erfolgsposition<br />
◮ sonst wie First Fit<br />
◮ Tendenz zu größerer Fragmentierung als First Fit
9 / 49<br />
Freispeicherliste<br />
Suchstrategien II<br />
Best Fit<br />
◮ Suche in Liste nach bestpassendstem Element (kleinstes<br />
Element, dessen Größe l ≥ m)<br />
◮ Suchaufwand!<br />
◮ Gefahr der Generierung unbenutzbar kleiner<br />
Restsegmente<br />
Worst Fit<br />
◮ Suche nach größtmöglichem Element, um Nachteil von<br />
Best Fit zu begegnen<br />
◮ → externe Fragmentierung !<br />
Bei Freigabe eines Blockes:<br />
◮ Markierung als frei<br />
◮ Vereinigung mit freien Nachbarblöcken, wenn möglich
10 / 49<br />
Freispeicherliste<br />
Techniken zur Effizienzsteigerung<br />
Verzögertes Vereinigen (Deferred Coalescing):<br />
◮ freigegebene Segmente nicht sofort mit freien<br />
Nachbarsegmenten vereinigen<br />
◮ Effizienzsteigerung wenn Objekte einer Größe angefordert<br />
und freigegeben werden<br />
◮ Vereinigung erst nach Verzögerung oder durch extra<br />
Aktivität<br />
◮ → Objektcache (Slab Allocator)<br />
Begrenzungsmarken (Boundary Tags)<br />
◮ Endebegrenzung jedes Segmentes durch zum Header<br />
identischen Footer<br />
◮ vereinfacht Vereinigung mit unmittelbar vorangehendem<br />
(freien) Nachbarblock<br />
◮ Problem: Table Fragmentation
11 / 49<br />
Freispeicherliste<br />
Techniken zur Effizienzsteigerung II<br />
Zusätzliche Verkettung freier Segmente<br />
◮ schnellere Suche<br />
◮ kein zusätzlicher Speicherplatz nötig, da nur im<br />
ungenutzten Speicher angelegt<br />
H F H F H F H F H F<br />
...<br />
Abbildung: Zusätzliche Verkettung freier Segmente
12 / 49<br />
Getrennte Freispeicherlisten (Segregated Fits)<br />
Idee: Array von Listen unterschiedlicher<br />
Segmentgröße(nklassen), um Suchaufwand zu reduzieren<br />
Variante 1: Einfacher getrennter Speicher (Simple Segregated<br />
Storage)<br />
◮ eine Liste pro Segmentgröße<br />
◮ keine <strong>Teil</strong>ung von Segmenten<br />
◮ Liste leer → 1-2 Seiten mittels sbrk() anfordern, in<br />
gleichgroße Blöcke teilen, in Liste einordnen<br />
◮ kein Transfer zwischen Listen ( keine Vereinigung mit<br />
benachbarten Segmenten)<br />
◮ ziemlich effizient im durchschnittlichen Fall<br />
◮ Worst Case?
Getrennte Freispeicherlisten (Segregated Fits)<br />
13 / 49<br />
Variante 2: Getrennte Fits<br />
◮ Liste leer → Liste mit nächster Größe durchsucht, <strong>Teil</strong>ung<br />
eines gefundenen Segments<br />
a) exakte Listen<br />
b) Strikte Größenklassen mit Rundung<br />
c) Listen mit Größenintervallen<br />
◮ ggf. Wiederholung der Suche in Listen mit größeren<br />
Segmenten<br />
◮ Vereinigung benachbarter freier Segmente (sofort oder<br />
verzögert)
14 / 49<br />
Buddy-Verfahren<br />
Idee: System reicht Blöcke fester Größe k = 2 N Bytes aus<br />
◮ N Listen mit (exakter) Segmentgröße<br />
◮ ausgereicht wird stets ein Block mit der Größe, die die<br />
Anforderung am knappsten befriedigt (z. B. Anforderung 47<br />
KiB → Auslieferung 64 KiB)<br />
◮ wenn kein Block passender Größe vorhanden:<br />
1. <strong>Teil</strong>ung eines nächstgrößeren (freien) Blockes<br />
2. Auslieferung einer Hälfte<br />
3. andere Hälfte (der „Buddy“) wird als frei in die<br />
entsprechende Liste einsortiert<br />
◮ Initial enthält eine Liste genau einen Block, den gesamten<br />
(freien) Hauptspeicher<br />
◮ Bei Rückgabe wird geprüft, ob der Block ggf. mit seinem<br />
Buddy vereinigt werden kann (und in der Liste der<br />
nächstgrößeren Blöcke eingeordnet werden kann)
15 / 49<br />
Buddy-Verfahren<br />
Beurteilung<br />
◮ Aufwand bei Rückgabe des Speichers geringer als mit<br />
Freispeicherliste<br />
◮ wirkt externer Fragmentierung entgegen, da stets maximal<br />
wieder vereinigt wird<br />
◮ Hauptnachteil: Speicherplatzverschwendung (Verschnitt;<br />
interne Fragmentierung)
16 / 49<br />
Virtueller Speicher<br />
Motivation<br />
Ziel:<br />
◮ Schutz der Aktivitäten voreinander<br />
◮ die Größe des Hauptspeichers übersteigende<br />
Prozesssysteme<br />
Konzept:<br />
◮ „Erweiterung“ des Hauptspeichers durch Massenspeicher<br />
◮ Privatisierung der Adressräume<br />
◮ Partitionierung der virtuellen und des physischen<br />
Adressraums (einheitliche, feste Größe; z. B. 4 KiB)
17 / 49<br />
Virtueller Speicher<br />
Seiten vs. Kacheln<br />
◮ virtueller Adressraum → logische Seiten (virtuelle Seiten,<br />
Pages)<br />
◮ physischer Adressraum → (gleichgroße) Kacheln<br />
(Seitenrahmen, Page Frames)
18 / 49<br />
Virtueller Speicher<br />
Seiten vs. Kacheln<br />
Seiten<br />
virtueller Speicher<br />
Prozeß 1<br />
A<br />
B MMU+OS<br />
C<br />
D<br />
Prozeß 2<br />
P<br />
Q<br />
R<br />
physischer Hauptspeicher<br />
P<br />
A<br />
B<br />
C<br />
frei Kacheln<br />
Q<br />
R<br />
frei<br />
D<br />
...<br />
...<br />
Abbildung: Abbildung logischer Seiten auf physische Kacheln
Gestreute Speicherung<br />
Umsetzung virtueller in physische Adresse<br />
19 / 49<br />
◮ bei jeder (!) Speicherreferenz<br />
◮ ausgeführt durch Hardware (Memory Management Unit –<br />
MMU im Prozessor)<br />
◮ Indexierung einer Tabelle (Seitentabelle, Page Table)<br />
◮ Seitentabelle durch BS verwaltet, existiert pro Prozess<br />
Seitennummer<br />
virtuelle Adresse<br />
Index<br />
0x0000<br />
0x1000<br />
Hauptspeicher<br />
Seitenadressen Prot P<br />
0x8000<br />
0x1000<br />
RW<br />
RO<br />
1<br />
0<br />
0x3000 RWX 1<br />
...<br />
...<br />
...<br />
0x4000 RO 1<br />
Seitentabelle<br />
+<br />
0x2000<br />
physische<br />
Adresse<br />
0x4000<br />
...<br />
selektiertes<br />
Wort
Seitentabelleneintrag (Page Table Entry – PTE)<br />
Aufbau (Beispiel)<br />
20 / 49<br />
C<br />
D<br />
R<br />
M<br />
Prot<br />
P Page Frame Number<br />
◮ PFN – Page Frame Number – Adresse der<br />
entsprechenden physischen Kachel<br />
◮ P – Present-Bit – Seite ist im Hauptspeicher (oder auf<br />
Massenspeicher ausgelagert)<br />
◮ Prot – Protection – Lese-/Schreib-/Ausführungs-Operation<br />
sind (nicht) erlaubt<br />
◮ M – Modified (“dirty”) – Kachel wurde beschrieben (→<br />
muss vor Auslagerung auf Massenspeicher<br />
zurückgeschrieben werden)<br />
◮ R – Referenced – Seite wurde durch den Prozess<br />
(irgendwann einmal) gelesen, referenziert<br />
◮ CD – Cache disable – Seiteninhalt darf nicht gecacht<br />
werden (wichtig bei memory-mapped devices)
21 / 49<br />
Größe der einstufigen Seitentabelle<br />
Problem: Größe der Seitentabelle (muß hintereinander im<br />
Speicher stehen)<br />
Beispiel<br />
Seitengröße 4 KiB, 32 Bit Adressbreite<br />
→ Index 12 Bit (2 12 = 4096)<br />
→ Seitennummer 20 Bit groß (32-12=20)<br />
→ Seitentabelle kann 2 20 Einträge enthalten<br />
→ resultierende Größe der Seitentabelle 4 MByte (pro<br />
Prozess!)
22 / 49<br />
Größe der Seitentabelle<br />
Lösung: Baum von Seitentabellen (→ Hierarchie)<br />
◮ langsamerer Zugriff, da mehrere Subtabellen aufgesucht<br />
werden müssen<br />
◮ Subtabellen dafür kürzer und flexibler (auf Anforderung<br />
anlegbar)<br />
◮ zwei- (Intel i386), drei- und vierstufige Hierarchien<br />
◮ Verbesserung des Timings durch einen Cache, der<br />
Adressumsetzungen virtuell → physisch aufbewahrt:<br />
Translation Lookaside Buffer (TLB)
Beispiel: Zweistufige Seitentabelle (i386)<br />
23 / 49<br />
PD−Index<br />
PT−Index<br />
Byte−Index<br />
virtuelle<br />
Adresse<br />
Register CR3<br />
gewähltes Byte<br />
gewählte<br />
Seite<br />
PD−Eintrag<br />
PTE<br />
Page Directory<br />
1024 Einträge<br />
Page Tables<br />
1024 Einträge<br />
physischer Adreßraum
Demand Paging<br />
24 / 49<br />
Idee: Benötigte Seiten werden erst bei Bedarf in den<br />
Hauptspeicher geladen. Ist der physische Speicher restlos<br />
ausgenutzt, so muss zuvor eine andere Seite ausgelagert<br />
werden.<br />
Prinzipieller Ablauf<br />
1. Prozess referenziert eine Adresse (neuer Befehl, Zugriff<br />
auf Datum)<br />
2. MMU führt Adressübersetzung aus<br />
3. BS prüft:<br />
◮ referenzierte Seite im physischen Speicher → Ausführung<br />
der Instruktion, Weiterarbeit<br />
◮ referenzierte Seite momentan ausgelagert → Seitenfehler<br />
(Page Fault, Software-Interrupt)
25 / 49<br />
Seitenfehler (Pagefault)<br />
1. Prozess wird angehalten (blockiert)<br />
2. BS sucht freie HS-Kachel<br />
3. falls keine freie HS-Kachel verfügbar → Auswahl einer<br />
auszulagernden Seite, Auslagerung auf Festplatte<br />
4. Einlesen der referenzierten Seite in (nun) freie HS-Kachel<br />
von Festplatte<br />
5. Weiterarbeit des blockierten Prozesses<br />
Pro Seitenfehler bis zu 2 Festplattenzugriffe notwendig!<br />
Einfachere Alternative: Swapping: ganze Prozesse werden<br />
ausgelagert!
26 / 49<br />
Einlagerungsstrategien<br />
◮ Demand Paging: Einblenden einer Seite bei Referenz<br />
(spätestmöglicher Zeitpunkt, Lazy Evaluation)<br />
◮ Prepaging: Seiten werden im voraus eingeblendet.<br />
Sinnvoll bei kontinuierlicher Ablage auf Massenspeicher;<br />
angewandt z.B. bei Start eines neuen Prozesses<br />
(Windows NT).
Seitenaustauschverfahren<br />
27 / 49<br />
Frage: Welche Seite soll ausgelagert werden?<br />
◮ Ähnlichkeit zur Ersetzungsstrategie in Caches<br />
◮ Strafe (Penalty) sehr hoch, da Massenspeicherzugriff:<br />
◮ 1 Instruktion benötigt ca. 0.3 ns bei 3 GHz Takt<br />
◮ 1 Festplattenoperation benötigt ca. 10 ms<br />
◮ → Zeit für ≈ 30 · 10 6 Instruktionen<br />
◮ Worst Case?
28 / 49<br />
Seitenaustauschverfahren<br />
Optimales Verfahren; LRU<br />
Optimales Verfahren<br />
◮ lagert diejenige Seite aus, die am längsten nicht benötigt<br />
wird (in Zukunft)<br />
◮ schwierig ohne eingebauten Hellseher<br />
◮ wichtig zum Vergleich realer Verfahren<br />
Least Recenty Used (LRU)<br />
◮ Heuristik: Seiten die lange nicht referenziert wurden,<br />
werden auch in Zukunft kaum gebraucht<br />
◮ exaktes LRU schwierig („älteste Seite auslagern“)<br />
◮ vgl. Cache<br />
◮ Approximation: NRU
29 / 49<br />
Seitenaustauschverfahren<br />
Not Recently Used (NRU)<br />
Not Recenty Used (NRU)<br />
◮ Ausnutzung des Referenced- und des Modified-Bits im<br />
Seitentabelleneintrag<br />
◮ periodisches Rücksetzen des R-Bits durch BS (z.B. durch<br />
Timerinterrupt gesteuert)<br />
◮ R-Bit wird automatisch (durch MMU) gesetzt, sobald Seite<br />
referenziert wurde<br />
◮ M-Bit gesetzt, wenn Seiteninhalt modifiziert wurde („dirty“)<br />
→ vor Auslagerung zurückschreiben
Seitenaustauschverfahren<br />
Not Recently Used (NRU), contd.<br />
◮ 4 Klassen von Seiten unterscheidbar:<br />
R M Beschreibung<br />
0 0 Seite wurde nicht referenziert<br />
0 1 Seite wurde lange nicht referenziert, aber (irgendwann)<br />
verändert<br />
1 0 Seite wurde referenziert, aber nicht modifiziert<br />
1 1 Seite wurde referenziert und geändert<br />
◮ bei Bedarf zunächst Auslagerung von {00}-Seiten<br />
◮ wenn keine verfügbar, dann {01}-Seiten, dann {10}-Seiten,<br />
usw.<br />
30 / 49
Seitenaustauschverfahren<br />
FIFO; 2nd Chance<br />
31 / 49<br />
First In, First Out (FIFO)<br />
◮ Idee: ältere Seiten zuerst auslagern<br />
◮ keine Berücksichtigung der Referenz<br />
Second Chance<br />
◮ verbessert FIFO<br />
◮ Auslagerungskandidat (AK): älteste Seite<br />
◮ R == 0 → Seite wird ausgelagert<br />
◮ R == 1 → R := 0, Kandidat: nächstälteste Seite<br />
◮ Anordnung der Seiten in Ringliste, Zeiger auf AK →<br />
„Uhralgorithmus“
Seitenaustauschverfahren<br />
NFU; Aging<br />
32 / 49<br />
Not Frequently Used (NFU)<br />
◮ Betrachtung der Referenzierungshäufigkeit<br />
◮ pro Seite ein Zähler, periodisches Aufaddieren des R-Bits<br />
◮ Auslagerung der am seltensten genutzten Seite (kleinster<br />
Zählerstand)<br />
◮ später eingelagerte Seiten benachteiligt<br />
◮ benötigt: Vergessen veralteter Zählerstände<br />
Aging<br />
◮ Modifikation von NFU:<br />
◮ alle Zähler vor Aufaddieren des R-Bits 1 Bit nach rechts<br />
geschoben<br />
◮ R-Bit wird an höchste Bitposition des Zählers geschrieben
Seitenaustauschverfahren<br />
Aging, contd.<br />
Tick<br />
1 2 3 4 5<br />
R−Bits 1 0 1 0 1 1 1 1 0 0 1 0 1 1 0 1 0 1 1 0 0 0 1 0 0 1 1 0 0 0<br />
0<br />
10000000 11000000 11100000<br />
11110000<br />
01111000<br />
1<br />
00000000<br />
10000000<br />
11000000<br />
01100000<br />
10110000<br />
2<br />
10000000<br />
01000000<br />
00100000<br />
00010000<br />
10001000<br />
3<br />
00000000<br />
00000000<br />
10000000<br />
01000000<br />
00100000<br />
4<br />
10000000<br />
11000000<br />
01100000<br />
10110000<br />
01011000<br />
5<br />
10000000<br />
01000000<br />
10100000<br />
01010000<br />
00101000<br />
Abbildung: Beispiel für den Aging-Algorithmus<br />
◮ Shift-Operation realisiert „Vergessen“ alter Zählerstände<br />
◮ Häufigkeit und Zeitpunkt der Referenzierung relevant<br />
33 / 49
34 / 49<br />
Konzept der Arbeitsmenge (Working Set)<br />
Empirische Beobachtung: eine bestimmte Anzahl<br />
eingeblendeter Seiten ist optimal.<br />
◮ Anzahl zu gering → hohe Seitenfehlerrate,<br />
◮ Anzahl zu groß → Speicherverschwendung,<br />
möglicherweise kein Prozess mehr bereit.<br />
Prinzip: Die Arbeitsmenge W (t, ∆) sind diejenigen Seiten<br />
eines Prozesses, die zwischen dem aktuellen Zeitpunkt t und<br />
einem Zeitpunkt t − ∆ in der Vergangenheit referenziert<br />
wurden.
Beispiel für eine Arbeitsmenge<br />
Referenz-<br />
∆<br />
kette 2 3 4 5<br />
24 24 24 24 24<br />
15 24, 15 24,15 24,15 24,15<br />
18 15, 18 24,15,18 24,15,18 24,15,18<br />
23 18, 23 15,18,23 24,15,18,23 24,15,18,23<br />
24 23, 24 18,23,24 ⋆ ⋆<br />
17 24, 17 23, 24, 17 18, 23, 24, 17 15, 18, 23, 24, 17<br />
18 17, 18 24, 17, 18 ⋆ 23, 24, 17, 18<br />
24 18, 24 ⋆ 17, 18, 24 ⋆<br />
18 ⋆ 24, 18 ⋆ 17, 24, 18<br />
17 18, 17 24, 18, 17 ⋆ ⋆<br />
17 17 18, 17 ⋆ ⋆<br />
15 17, 15 17, 15 18, 17, 15 24, 18, 17, 15<br />
24 15, 24 17, 15, 24 17, 15, 24 ⋆<br />
17 24, 17 ⋆ ⋆ 17, 15, 24<br />
24 ⋆ 27, 24 ⋆ ⋆<br />
18 24, 18 17, 24, 18 17, 24, 18 15, 17, 24, 18<br />
Tabelle: Beispiel der Entwicklung der Arbeitsmenge eines Prozesses<br />
für unterschiedliche ∆ (Bach: The Design of the UNIX Operating<br />
System. 1986, S. 287) 35 / 49
Konzept der Arbeitsmenge (Working Set)<br />
36 / 49<br />
Es gilt<br />
W (t, ∆ + 1) ⊇ W (t, ∆)<br />
d.h., die Arbeitsmenge wächst monoton mit ∆. Weiterhin gilt für<br />
die Menge der referenzierten Seiten<br />
1 ≤ W (t, ∆) ≤ min(∆, N)<br />
wobei N die Gesamtzahl der referenzierten Seiten eines<br />
Prozesses bezeichnet. Der Parameter ∆ kann als<br />
Fenstergröße in die Referenzierungsvergangenheit des<br />
Prozesses aufgefasst werden.
Abhängigkeit der Größe der Arbeitsmenge von ∆<br />
|W (t, ∆)|<br />
∆ 0 ∆<br />
37 / 49
38 / 49<br />
Abhängigkeit der Größe der Arbeitsmenge von ∆<br />
◮ „gesättigtes“ Verhalten: ab einem bestimmten Punkt (∆ 0 )<br />
ändert sich die Größe der Arbeitsmenge nicht mehr<br />
gravierend (Ursache: Lokalitätsprinzip)<br />
◮ minimale Größe der Arbeitsmenge |W (t, ∆ 0 )|, bestimmt<br />
die Grenze zwischen niedriger und hoher Pagefault-Rate<br />
◮ Working Set unterliegt zyklischen Veränderungen; man<br />
unterscheidet transiente und stabile Zustände
Idee für eine Ersetzungsstrategie<br />
. . . basierend auf dem Working Set<br />
39 / 49<br />
◮ W für jeden Prozess beobachten<br />
◮ zyklisch alle diejenigen Seiten eines Prozesses entfernen,<br />
die nicht zu W gehören<br />
◮ Prozess darf nur aktiviert werden, wenn seine<br />
Arbeitsmenge im Hauptspeicher eingeblendet<br />
Probleme:<br />
◮ exakte Messung, Logging des WS aufwendig <br />
Approximation<br />
◮ Wahl von ∆:<br />
◮ zu klein → PF-Rate des Prozesses steigt<br />
◮ zu groß → Speicherverschwendung<br />
◮ keine Adaption bei Größenänderung der Arbeitsmenge
Beladys Anomalie<br />
Vergrößerung von W führt normalerweise zu Verringerung der<br />
Page-Fault-Rate des betroffenen Prozesses, jedoch . . .<br />
◮ 5 virtuelle Seiten<br />
◮ Ersetzungsstrategie FIFO<br />
◮ (willkürliche ) Referenzierungskette: 0 → 1 → 2 → 3 → 0<br />
→ 1 → 4 → 0 → 1 → 2 → 3 → 4<br />
Ref.−Kette<br />
0 1 2 3 0 1 4 0 1 2 3 4<br />
jüngste Seite<br />
älteste Seite<br />
PF<br />
0 1<br />
0<br />
2 3 0 1 4 4 4 2 3 3<br />
1 2 3 0<br />
0 1 2 3<br />
1 1 1 4 2<br />
0 0 0 1 4<br />
2<br />
4<br />
Abbildung: Beladys Beispiel mit W = 3 Seitenrahmen<br />
40 / 49
Beladys Anomalie, contd.<br />
41 / 49<br />
Ref.−Kette<br />
0 1 2 3 0 1 4 0 1 2 3 4<br />
jüngste Seite 0 1 2 3 3 3 4 0 1 2 3<br />
0 1 2 2 2 3 4 0 1 2<br />
0 1 1 1 2 3 4 0 1<br />
älteste Seite 0 0 0 1 2 3 4 0<br />
4<br />
3<br />
2<br />
1<br />
PF<br />
Abbildung: Beladys Beispiel mit W = 4 Seitenrahmen<br />
◮ Vergrößerung des WS führt zu Erhöhung der PF-Rate<br />
(W = 3 → 9PF, W = 4 → 10PF)<br />
◮ unerwartetes Verhalten, Anomalie<br />
◮ konstruiertes Beispiel<br />
◮ abhängig vom Seitenersetzungsverfahren; LRU<br />
unempfindlich
42 / 49<br />
Weitere Aspekte zur Seitenersetzung<br />
◮ optimale Seitengröße?<br />
◮ lokale vs. globale Ersetzungsstrategien<br />
◮ variable vs. konstante Größe des Working Set<br />
◮ viele weitere Ersetzungsstrategien<br />
◮ alternative Mechanismen der Suche in Seitentabellen
Schnittstelle zum Betriebssystem UNIX<br />
malloc() und free()<br />
◮ Semantik: Anforderung von Heap-Speicher, bzw. dessen<br />
Rückgabe<br />
◮ Funktionen der C-Bibliothek (→ portabel)<br />
◮ eine der Hauptquellen für Programmfehler ist fehlerhafter<br />
Umgang mit diesen Funktionen<br />
◮ weitere Funktionen: realloc(), calloc()<br />
◮ unter UNIX gewöhnlich mittels brk() realisiert (jedoch<br />
auch mit mmap())<br />
◮ Implementierung stark systemabhängig<br />
◮ viele Allokatoren vergrößern Heap zwar, verkleinern<br />
jedoch nicht (Optimierung)<br />
◮ Seiten werden bei malloc() weder initialisiert noch<br />
zwangsweise eingeblendet<br />
◮ bekannteste Implementation: Doug Lea’s Allocator<br />
43 / 49
Speicherabbild eines Prozesses<br />
44 / 49<br />
High<br />
Umgebung, Argumente<br />
Stack<br />
Heap<br />
uninitialisierte Daten<br />
(BSS)<br />
"break"<br />
null−initialisiert<br />
Low<br />
initialisierte Daten<br />
Text<br />
aus Datei eingelesen<br />
durch exec()
Der Systemruf brk()<br />
45 / 49<br />
int brk(void *end_data_segment);<br />
◮ setzt das Ende des Heaps auf end_data_segment,<br />
vorausgesetzt<br />
◮ Wert ist plausibel,<br />
◮ das System hat noch genügend Speicher,<br />
◮ maximale Heapgröße des Prozesses wird nicht<br />
überschritten<br />
◮ genutzt z. B. zur Implementierung von malloc() & Co.<br />
◮ weitere Funktion der C-Bibliothek: sbrk()<br />
◮ malloc() und brk() nicht gleichzeitig verwendbar<br />
◮ im Vergleich zu malloc() viel elementarer
46 / 49<br />
Stackanforderung mittels alloca()<br />
void *alloca(size_t size);<br />
◮ alloziiert size Bytes auf dem Stack (!)<br />
◮ keine Rückgabefunktion benötigt (Warum?)<br />
◮ nicht für alle Systeme verfügbar<br />
“The alloca function is machine and compiler<br />
dependent. On many systems its implementation<br />
is buggy. Its use is discouraged.” (man alloca,<br />
2.6er Linux-System)<br />
◮ Implementierung durch Inline-Code ( nicht als Argument<br />
einer Parameterliste nutzbar)
47 / 49<br />
Ausschalten des Pagings (Pinning)<br />
◮ Verhinderung des Auslagerns<br />
a) einzelner Seiten mittels mlock()<br />
b) des gesamten Adressraums mittels mlockall()<br />
◮ für (weiche) Echtzeit- und sicherheitskritische<br />
Applikationen<br />
◮ Rückbau mit munlock()/munlockall()<br />
◮ vergrößert Pagefault-Rate für nichtpinnende Prozesse
48 / 49<br />
Memory-mapped Files<br />
aka ‘speichereingeblendete Dateien’<br />
◮ mmap(), munmap(), mremap(), msync()<br />
◮ blendet Dateien (oder Geräte) in den Hauptspeicher ein<br />
◮ Granularität: Seiten<br />
◮ gemeinsame oder exklusive Einblendung möglich<br />
◮ d. h. eingeblendete Dateien werden wie Hauptspeicher<br />
manipuliert (ersetzt klassische<br />
open/read/write/close-Schnittstelle)<br />
◮ modern
49 / 49<br />
Was haben wir gelernt?<br />
◮ Hauptspeicherverwaltung: Bitmaps, Listen,<br />
Buddy-Verfahren<br />
◮ Virtueller Speicher: Funktionsweise, Ablauf des Pagefault,<br />
relevante Datenstrukturen<br />
◮ Ersetzungsstrategien (LFU, NFU, Aging & Co., Working<br />
Set )<br />
◮ API zum Hauptspeicher von unix-artigen BS