mirror of
https://github.com/theoleuthardt/hwr-notes.git
synced 2026-06-06 02:11:08 +00:00
140 lines
No EOL
12 KiB
Markdown
140 lines
No EOL
12 KiB
Markdown
# Zusammenfassung: Speicherverwaltung
|
||
## 1. Einführung: Die Direkte Speicherverwaltung
|
||
Die einfachste und historisch älteste Form der Speicherverwaltung ist die direkte Verwaltung.
|
||
- **Grundprinzip:** Alle Adressen, die im Programmcode stehen, entsprechen direkt den physikalischen Adressen im Hauptspeicher (RAM). Es gibt keine Übersetzungsschicht.
|
||
- **Beispiel:** Der Assembler-Befehl `mov AX, 42` bedeutet, dass der Prozessor direkt auf die physikalische Speicherzelle Nr. 42 zugreift und deren Inhalt in das Register AX lädt.
|
||
### Historische Speichertypen
|
||
Frühere Computer unterschieden strikt zwei Arten von Speicher:
|
||
1. **ROM (Read-Only-Memory):** Ein kleiner Speicher (ca. 64 KiB), der nicht überschrieben werden konnte. Er enthielt Boot-Funktionen, Treiber und Teile des Betriebssystems.
|
||
2. **RAM (Random-Access-Memory):** Der große Arbeitsspeicher für das Betriebssystem und die Benutzerprogramme.
|
||
### Organisation
|
||
Wenn nur ein einziges Benutzerprogramm und das Betriebssystem (OS) im Speicher sind, gab es drei Organisationsformen:
|
||
1. OS im RAM (unten), Benutzerprogramm darüber.
|
||
2. OS im ROM (oben), Benutzerprogramm im RAM.
|
||
3. Treiber im ROM, OS und Benutzerprogramm im RAM.
|
||
### Nachteile der direkten Verwaltung
|
||
Dieses Modell stößt schnell an Grenzen:
|
||
1. **Mangelnder Schutz:** Ein Programm kann versehentlich das Betriebssystem oder andere Programme beschädigen, da es Zugriff auf jedes physikalische Byte hat.
|
||
2. **Kein echtes Multitasking:** Es ist fast unmöglich, mehrere Programme gleichzeitig laufen zu lassen. Wenn zwei Programme hartkodierte Adressen nutzen (z.B. beide wollen an Adresse 1000 starten), können sie nicht gleichzeitig im Speicher liegen.
|
||
3. **Größenbeschränkung:** Das gesamte Programm muss vollständig in den physikalischen Speicher passen ("The whole program must be presented in memory").
|
||
## 2. Die erste Lösung: Adressräume & Swapping
|
||
Um die Probleme der direkten Verwaltung zu lösen, wurden Adressräume eingeführt. Ein Adressraum ist die Menge aller Adressen, die ein Prozess verwenden darf. Jeder Prozess erhält seinen eigenen, isolierten Raum.
|
||
### Hardware-Unterstützung (Basis & Limit)
|
||
Der Prozessor nutzt zwei spezielle Register zur Verwaltung:
|
||
1. **Basisregister:** Enthält die physikalische Startadresse des Programms.
|
||
2. **Grenzwertregister (Limit):** Enthält die Gesamtlänge des Programms.
|
||
- **Berechnung:** Die effektive physikalische Adresse = Programmadresse + Basisregister.
|
||
- **Schutz:** Die Hardware prüft bei jedem Zugriff: Effektive Adresse ≤ Basis + Limit. Ist dies nicht der Fall, wird der Zugriff verweigert (Schutzverletzung).
|
||
### Das Konzept des Swapping (Auslagerung)
|
||
Da der Arbeitsspeicher selten groß genug ist, um alle Prozesse gleichzeitig vollständig zu halten, nutzt das OS "Swapping".
|
||
- **Vorgang:** Wenn der Platz knapp wird, wird ein inaktiver Prozess komplett auf die Festplatte geschrieben (ausgelagert) und ein anderer Prozess komplett in den Speicher geladen.
|
||
- **Problem der Fragmentierung:** Durch das ständige Ein- und Auslagern entstehen ungenutzte Lücken ("Löcher") zwischen den Prozessen. Der Speicher zerstückelt.
|
||
- **Lösung:** Das OS muss den Speicher defragmentieren (komprimieren), was jedoch sehr rechenaufwändig ist.
|
||
### Speicherzuweisungs-Algorithmen (Allocation Algorithms)
|
||
Wenn ein neuer Prozess geladen werden soll, muss das OS eine passende Lücke im RAM finden. Hierfür gibt es fünf klassische Strategien:
|
||
1. **First Fit:** Wählt die erste Lücke, die groß genug ist. Schnell, aber fragmentiert den Speicher vorne.
|
||
2. **Next Fit:** Beginnt die Suche dort, wo die letzte Zuweisung endete.
|
||
3. **Best Fit:** Sucht die kleinste Lücke, die gerade so ausreicht. Nachteil: Hinterlässt winzige, nutzlose Rest-Lücken.
|
||
4. **Worst Fit:** Wählt die größte verfügbare Lücke. Idee: Der Rest ist groß genug für weitere Prozesse.
|
||
5. **Quick Fit:** Hält separate Listen für häufig benötigte Lückengrößen bereit.
|
||
## 3. Virtuelle Speicherverwaltung (Paging)
|
||
Das ist der Standard in allen modernen Systemen (Windows, Linux, Android, macOS). Es entkoppelt die Sicht des Programms von der physikalischen Realität.
|
||
### Kernkonzepte
|
||
- **Virtueller Speicher:** Das Programm "sieht" einen perfekten, linearen Speicher, der in Pages (Seiten) unterteilt ist.
|
||
- **Physischer Speicher:** Der RAM ist in Frames (Seitenrahmen) unterteilt.
|
||
- **Mapping:** Es gilt immer: Größe Frame = Größe Page (Standard ist oft 4 KiB).
|
||
- **Vorteil:** Ein Programm kann größer sein als der physikalische Speicher. Die Seiten müssen nicht zusammenhängend im RAM liegen.
|
||
### MMU (Memory Management Unit)
|
||
Die MMU ist ein Hardware-Baustein direkt auf dem Prozessor-Chip.
|
||
- **Aufgabe:** Sie übersetzt bei jedem Speicherzugriff die virtuelle Adresse in eine physikalische Adresse.
|
||
- **Richtung:** Immer Virtuell → Physikalisch (niemals umgekehrt!).
|
||
### Berechnung der optimalen Seitengröße
|
||
Die Wahl der Seitengröße ist ein Kompromiss.
|
||
- **Kleine Seiten:** Weniger Verschnitt (interne Fragmentierung), aber riesige Verwaltungstabellen.
|
||
- **Große Seiten:** Kleine Tabellen, aber viel ungenutzter Platz am Ende der letzten Seite.
|
||
- **Formel:** p = √(2 · s · e)
|
||
- p: Seitengröße
|
||
- s: Durchschnittliche Prozessgröße
|
||
- e: Größe eines Seitentabellen-Eintrags
|
||
- Beispiel: Bei 1 MiB Programmgröße und 8 Byte Eintrag ergibt sich mathematisch eine optimale Größe von 4 KiB.
|
||
## 4. Datenstrukturen: Seitentabellen & TLB
|
||
### Die Seitentabelle (Page Table)
|
||
Jeder Prozess besitzt eine eigene Seitentabelle im RAM. Sie dient der MMU als Nachschlagewerk. Ein Eintrag in dieser Tabelle (typisch 32 Bit / 4 Byte) enthält komplexe Statusinformationen:
|
||
1. **Rahmennummer:** Die eigentliche physikalische Adresse im RAM (wo liegt die Seite?).
|
||
2. **Present/Absent Bit (P):**
|
||
- 1: Seite ist im RAM (Zugriff okay).
|
||
- 0: Seite ist nicht im RAM (löst Seitenfehler / Page Fault aus).
|
||
3. **Modified Bit (M) / Dirty Bit:**
|
||
- 1: Die Seite wurde verändert (geschrieben). Sie muss beim Entfernen auf die Festplatte zurückgesichert werden.
|
||
- 0: Seite ist sauber (identisch mit der Festplatte), kann einfach überschrieben werden.
|
||
4. **Referenced Bit (R):**
|
||
- 1: Seite wurde kürzlich gelesen oder beschrieben. Wichtig für Ersetzungs-Algorithmen. Das OS setzt dieses Bit periodisch auf 0 zurück.
|
||
5. **Schutz-Bits (RWX):** Definieren Rechte (Read, Write, Execute).
|
||
|
||
### Das Problem der Größe
|
||
Da jeder Prozess eine Tabelle braucht, kann dies viel Speicher kosten. Bei 32-Bit oder 64-Bit Systemen können Tabellen mehrere Megabyte groß werden (z.B. 4 MiB).
|
||
- **Lösung:** Mehrstufige Seitentabellen (Paged Page Tables).
|
||
### TLB (Translation Lookaside Buffer)
|
||
Da ein Zugriff auf die Seitentabelle im RAM langsam ist (Verdopplung der Zugriffszeit: 1x Tabelle lesen, 1x Daten lesen), nutzt die MMU einen Hardware-Cache namens TLB.
|
||
- Der TLB speichert die häufigsten Übersetzungen.
|
||
- Die MMU prüft zuerst den TLB. Nur bei einem "Miss" greift sie auf die langsame Tabelle im RAM zu.
|
||
## 5. Seitenersetzungs-Algorithmen (Page Replacement)
|
||
Wenn der physikalische Speicher voll ist und eine neue Seite geladen werden muss (Demand Paging), muss eine alte Seite weichen ("Opfer"). Welcher Algorithmus trifft diese Entscheidung?
|
||
### A. NRU (Not Recently Used)
|
||
Klassifiziert Seiten anhand der R- und M-Bits in 4 Klassen:
|
||
- **Klasse 0:** Nicht referenziert, nicht modifiziert. (Bestes Opfer).
|
||
- **Klasse 1:** Nicht referenziert, modifiziert.
|
||
- **Klasse 2:** Referenziert, nicht modifiziert.
|
||
- **Klasse 3:** Referenziert, modifiziert. (Schlechtes Opfer, wird oft gebraucht).
|
||
**Strategie:** Löscht zufällig eine Seite aus der niedrigsten vorhandenen Klasse. Einfach, aber mäßig effizient.
|
||
### B. FIFO (First-In-First-Out)
|
||
- **Strategie:** Führt eine Liste aller Seiten. Die älteste (zuerst geladene) Seite fliegt raus.
|
||
- **Nachteil:** Die älteste Seite kann eine wichtige Kernel-Bibliothek sein, die ständig benötigt wird. FIFO ist daher in Reinform ineffizient.
|
||
### C. Second Chance (SC)
|
||
Eine Verbesserung von FIFO. Prüft das R-Bit der ältesten Seite:
|
||
- **R=0:** Seite ist alt und unbenutzt → Raus.
|
||
- **R=1:** Seite ist alt, aber aktiv → R-Bit löschen, Seite ans Ende der Liste verschieben (wie neu geladen). Sie erhält eine "zweite Chance".
|
||
### D. Clock (Uhr-Algorithmus)
|
||
- Eine effizientere Implementierung von Second Chance mittels einer zirkulären Liste (wie ein Zifferblatt).
|
||
- Ein Zeiger dreht sich im Kreis. Trifft er auf R=1, setzt er es auf 0 und geht weiter. Trifft er auf R=0, wird die Seite ersetzt.
|
||
### E. LRU (Least Recently Used)
|
||
- **Idee:** Die Vergangenheit sagt die Zukunft voraus. Seiten, die lange nicht genutzt wurden, werden wohl auch bald nicht gebraucht.
|
||
- **Implementierung:** Theoretisch bräuchte man einen Zeitstempel bei jedem Zugriff (zu teuer).
|
||
- **Praxis:** Hardware-Zähler in der Seitentabelle oder Matrix-Methoden. Gilt als einer der besten Algorithmen.
|
||
### F. Working Set (WS)
|
||
- Definiert eine "Arbeitsmenge" an Seiten, die ein Prozess in einem Zeitfenster τ (z.B. 100ms) benötigt hat.
|
||
- **Strategie:** Entferne nur Seiten, die nicht zum aktuellen Working Set gehören. Verhindert "Thrashing" (das System ist nur noch mit Auslagern beschäftigt).
|
||
## 6. Der Ablauf eines Seitenfehlers (Page Fault)
|
||
Was passiert im Detail, wenn ein Prozess auf eine Adresse zugreift, deren Present-Bit 0 ist? Dies ist ein komplexer Vorgang in 11 Schritten:
|
||
1. **Trap:** Die Hardware bemerkt den Fehler. Ein Interrupt wird ausgelöst, der Programmzähler (PC) wird im Stack gesichert. Der Modus wechselt zu Kernel-Mode.
|
||
2. **Sichern:** Alle flüchtigen Informationen (Register) werden gespeichert.
|
||
3. **Identifikation:** Das OS ermittelt, welche virtuelle Adresse den Fehler verursacht hat (steht oft in einem Spezialregister der CPU).
|
||
4. **Validierung:** Das OS prüft: Ist die Adresse überhaupt gültig? Hat der Prozess Rechte dafür? Falls nein → Prozess-Abbruch (Segmentation Fault).
|
||
5. **Rahmensuche:** Das OS sucht einen freien physikalischen Rahmen. Falls keiner frei ist, muss der Seitenersetzungsalgorithmus (siehe Punkt 5) ausgeführt werden, um Platz zu schaffen.
|
||
6. **Auslagern (Eviction):** Wenn die "Opfer-Seite" modifiziert war (M=1), muss sie erst auf die Festplatte geschrieben werden.
|
||
7. **Kontextwechsel:** Da Festplattenzugriffe langsam sind, wird der aktuelle Prozess blockiert und ein anderer Prozess darf solange rechnen (CPU-Nutzung optimieren).
|
||
8. **Laden:** Die eigentlich angeforderte Seite wird nun von der Festplatte in den freien Rahmen geladen.
|
||
9. **Update:** Die Seitentabelle wird aktualisiert: Rahmennummer eintragen, Present-Bit auf 1 setzen.
|
||
10. **Wiederherstellung (Restore):** Die gesicherten Register des Prozesses werden wiederhergestellt. Der Programmzähler wird auf den Befehl zurückgesetzt, der den Fehler verursachte.
|
||
11. **Fortsetzung:** Der Befehl wird erneut ausgeführt – diesmal erfolgreich, da die Seite nun im RAM ist.
|
||
## 7. Segmente & Speicherschutz
|
||
Ein moderner Prozess-Adressraum ist nicht homogen, sondern in logische Segmente unterteilt, die unterschiedliche Rechte (Schutz-Bits) haben:
|
||
1. **Code-Segment (Text):** Enthält die Maschinenbefehle.
|
||
- Rechte: Nur Lesen und Ausführen (r-x). Schreiben ist verboten (verhindert selbst-modifizierenden Code).
|
||
2. **Daten-Segment:** Enthält globale Variablen.
|
||
- Rechte: Lesen und Schreiben (rw-). Ausführen verboten (Schutz vor Buffer-Overflow-Exploits).
|
||
3. **Stack-Segment:** Für lokale Variablen und Funktionsaufrufe. (rw-).
|
||
4. **Heap-Segment:** Für dynamisch angeforderten Speicher (malloc / new). (rw-).
|
||
### Segmentation Fault
|
||
Ein "Segfault" tritt auf, wenn ein Programm versucht, auf eine Adresse zuzugreifen, für die es keine Rechte hat (z.B. Schreiben in Code-Segment) oder die nicht existiert (z.B. Dereferenzierung eines Null-Zeigers).
|
||
## 8. Vergleich: Swapping vs. Paging
|
||
|
||
|Merkmal|Swapping (Veraltet)|Paging (Modern)|
|
||
|---|---|---|
|
||
|**Einheit**|Ganzer Prozess wird verschoben.|Einzelne Seiten (Teile) werden verschoben.|
|
||
|**Speicherart**|Nur bei direkter Speicherverwaltung nötig.|Nur bei virtueller Speicherverwaltung.|
|
||
|**Effizienz**|Gering (große Datenmengen, Fragmentierung).|Hoch (feingranular, nur benötigte Teile).|
|
||
|**Hardware**|Benötigt Basis-/Limit-Register.|Benötigt MMU und Seitentabellen.|
|
||
|
||
### Demand Paging
|
||
Moderne Systeme laden Seiten nicht im Voraus ("Prefetching"), sondern strikt nach Bedarf ("Demand"). Eine Seite wird erst geladen, wenn ein Page Fault auftritt. Das spart Speicher und I/O-Bandbreite. |