Hauptspeicher - Universität Ulm
Hauptspeicher - Universität Ulm
Hauptspeicher - Universität Ulm
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
4. <strong>Hauptspeicher</strong><br />
4.1 Einführung<br />
4.1.1 Anforderungen an die Speicherverwaltung<br />
• Partitionierung und Strukturierung des <strong>Hauptspeicher</strong>s:<br />
- Traditionell eine Partition pro Programm,<br />
- Halde, Keller, Code, Systembereiche, Puffer ....<br />
- statische und dynamische Unterteilung,<br />
• Speicherzuteilung:<br />
- New(), Malloc(), Prozeduraufruf, Load ...<br />
• Freispeichersammlung:<br />
- Copy Collectoren, Mark & Sweep ...<br />
• Auslagern von Programm(teil)en:<br />
- Overlay Techniken, Swapping, virtueller Speicher.<br />
1 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.1.2 Speicherhierarchie<br />
• Cache:<br />
- Teuer, flüchtiger Inhalt, Kapazitäten in Kilobyte, meist mehrstufig,<br />
- Beispiel Athlon XP: 128 kB L1 Cache, 256 kB L2 Cache (auf Chip).<br />
- On-Chip mit vollem CPU-Takt, Off-Chip mit halbem CPU-Takt.<br />
• <strong>Hauptspeicher</strong>:<br />
- flüchtiger Inhalt, schneller Zugriff (z.B. SDRAM 5 ns).<br />
- DDR 800 RAM theoretisch bis zu 3,2 GB/s.<br />
- Kapazität in Megabyte (z.B. 512 MB).<br />
• Plattenspeicher:<br />
- Kostengünstige persistente Speicherung.<br />
- Zugriffszeiten in Millisekunden (z.B. 7ms).<br />
- IDE Festplatten erreichen bis zu 50 MB/s.<br />
- Kapazität in Gigabyte (z.B. 200 GB).<br />
• Die Speicherverwaltung organisiert den Transfer<br />
zwischen den Ebenen.<br />
CPU<br />
Host-<br />
Brücke<br />
E/A-<br />
Brücke<br />
L1 Cache<br />
Daten Code<br />
L2 Cache<br />
<strong>Hauptspeicher</strong> <br />
Festplatten<br />
2 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.1.3 Begriffe<br />
• Speicherblock: Menge von fortlaufenden logischen Speicheradressen.<br />
• Partition = (größerer) Gesamtspeicherblock für ein Programm.<br />
• Swapping = Aus- und Wiedereinlagern von ganzer Partitionen auf Disk.<br />
• Physikalische (absolute) Speicheradresse: bezeichnet/zeigt in physisch<br />
vorhandenen <strong>Hauptspeicher</strong>.<br />
• Logische Speicheradresse: Position im HS aus Sicht des Programmes, unabhängig<br />
von der physikalischen Speicherorganisation.<br />
• Relative Speicheradresse: Position relativ zu einem bekannten Punkt im<br />
Programm.<br />
- im Prinzip eine spezielle logische Adresse,<br />
- meist relativ zum Programmzähler,<br />
- oder zum Programmbeginn,<br />
- für Sprünge und Aufrufe.<br />
3 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.1.4 Binden von Speicheradressen<br />
• Compiler erzeugt Objektdateien:<br />
- pro Modul/Klasse eine Objektdatei.<br />
- innerhalb der Objektdatei relative Adressierung.<br />
- übergreifende Aufrufe über Importtabelle realisiert.<br />
• Linker/Binder:<br />
- Löst Referenzen auf importierte Funktionen/Variablen/Klassen auf.<br />
- Bindet Objektdateien zu einem ausführbaren Programm.<br />
- Prüft die Konsistenz der Schnittstellen.<br />
Lader:<br />
- bringt Programm zur Ausführung in den <strong>Hauptspeicher</strong>,<br />
- reloziert das Objektmodul, bzw. passt die Adressen an.<br />
- Anbinden von Standarddateien.<br />
4 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Adressbindung zum Übersetzungs- oder Linkagezeitpunkt:<br />
- fest „verdrahtete“, eingetragene Adresse im ausführbaren Programm.<br />
- Programm. muss an eine bestimmte Adresse geladen werden.<br />
� Konflikte bei Mehrprogrammbetrieb<br />
int main() {<br />
GetVersion();<br />
}<br />
main:<br />
call [pc-256]<br />
<strong>Hauptspeicher</strong><br />
kernel32.dll<br />
GetVersion<br />
0x4711<br />
test.exe<br />
0x4711<br />
5 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
-256
• Adressbindung zur Ladezeit:<br />
- Funktionstabelle mit importierten Funktionen wird vom Lader ausgefüllt.<br />
- Verweise auf externe Variablen werden aufgelöst<br />
- ESD - "External Symbol Dictionary" ...<br />
• Adressbindung zur Laufzeit:<br />
- erlaubt die Relozierung/Verschiebung des Programms zur Laufzeit,<br />
- Evtl. Verbindung zu shared Libraries und gemeinsamem Speicher,<br />
- Evtl. mithilfe der Memory Management Unit im Prozessor.<br />
- logische versus physikalische Adressen.<br />
CPU<br />
logische<br />
Adresse<br />
4711<br />
+<br />
MMU<br />
Adressübersetzung<br />
10000<br />
phys.<br />
Adresse<br />
14711<br />
<strong>Hauptspeicher</strong><br />
6 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.2 Anforderungen an die <strong>Hauptspeicher</strong>verwaltung<br />
• Ausgangssituation: Mehrprogrammbetrieb<br />
- mehrere Programme teilen sich den <strong>Hauptspeicher</strong>.<br />
- vorab ist unklar, welche Programme zu einem Zeitpunkt geladen sind.<br />
• Zuteilung von Speicherblöcken:<br />
- Schnell, und mit möglichst geringem Verschnitt.<br />
- Berücksichtigen von allfälligen Speicherquoten,<br />
• Freigabe von Speicherblöcken:<br />
- Aufräumen beim Terminieren eines Programmes.<br />
- manuelles oder automatisches Einsammeln.<br />
• Aus- und Einlagern von Programmen:<br />
- inaktive Programme und Speicherseiten auslagern.<br />
- somit bessere Ausnutzung des HS & CPU.<br />
7 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Relozierung:<br />
- Wiedereinlagern eines Programms kann an anderer Adresse erfolgen.<br />
- somit muss Programm relozierbar sein und alle Zeiger angepasst werden.<br />
- benötigt HW-Unterstützung (z.B. Segmente).<br />
- Relozierung auch zur Kompaktifizierung.<br />
• Gemeinsame Nutzung von <strong>Hauptspeicher</strong>:<br />
- Kooperation auf gemeinsamen Daten (Shared Memory).<br />
- vermeiden von Code-Redundanz,<br />
- mit Zugriffskontrolle,<br />
• Speicherschutz:<br />
- Betriebssystem in der Regel geschützt.<br />
- Schutz gegen ungewollte/absichtliche Störungen durch andere Progr.<br />
- Zugriff auf Speicher fremder Prg. nur mit besonderer Genehmigung.<br />
- Unterstützung durch Hardware (z. B. Segmente).<br />
- typsichere Sprachen von Vorteil (z.B. Java).<br />
8 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Logische Organisation :<br />
- Der <strong>Hauptspeicher</strong> ist als linearer Adressraum aufgebaut.<br />
- Programme sind üblicherweise modular realisiert.<br />
- Segmente bieten passende logische Struktur:<br />
- gemeinsame Nutzung gewisser Bereiche<br />
- verschiedene Schutzkategorien.<br />
Physikalische Organisation:<br />
- Speicher des Rechners in typischerweise in 3 Ebenen unterteilt (Cache, <strong>Hauptspeicher</strong> und<br />
Festplatte),<br />
- Informationsfluss zwischen diesen beiden Ebenen ist Aufgabe der Speicherverwaltung und<br />
der Hardware,<br />
- Anwendungsprogramme erhalten eine konsistente Speichersicht.<br />
• Virtueller Speicher:<br />
- Eventuell Abbildung logischer Adressen auf physikalische,<br />
- Verschiedene Overlaytechniken,<br />
- Segmentierung oder Paging.<br />
9 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.3 Partitionen im <strong>Hauptspeicher</strong><br />
Multiprogramming :<br />
- Ziel: Überlappen von E/A-Operationen und Verarbeitung,<br />
- Mehrere Programme werden gleichzeitig in versch. Partitionen gehalten,<br />
- Je nach BS können Partitionen auch geswappt werden (Auslagern),<br />
- Die Programme müssen voreinander geschützt werden,<br />
- Ältere Betriebssysteme kannten noch keinen virtuellen Speicher, sondern verwendeten eine<br />
Aufteilung des <strong>Hauptspeicher</strong>s in Partitionen.<br />
4.3.1 Statische Partitionierung<br />
• Statische Unterteilung des <strong>Hauptspeicher</strong>s in gleich große oder variabel große<br />
Partitionen. Jedes Programm erhält eine eigene Partition.<br />
• Während der Laufzeit kann diese Zuordnung nicht mehr verändert werden.<br />
• Es wird die kleinste Partition zugewiesen in die das Programm hineinpasst.<br />
• Sind alle Partitionen belegt, so warten Prg. in einer Zuteilungsschlange.<br />
10 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
Partitionen fester Größe (z.B. 8<br />
MB) mit mehreren Warteschlangen:<br />
Warteschlangen<br />
<strong>Hauptspeicher</strong><br />
Partition 4<br />
Partition 3<br />
Partition 2<br />
Partition 1<br />
Betriebssystem<br />
Warteschlange<br />
(wartende Prgs.)<br />
• einfach implementierbar.<br />
• maximale Anzahl Programme festgelegt.<br />
• Der Speicherbedarf muss vorab bekannt sein.<br />
• Ungenutzter Platz in einer Partition ist verloren<br />
� interne Fragmentierung/Speicherverschnitt<br />
Variable Partitionen und eine<br />
Warteschlange:<br />
<strong>Hauptspeicher</strong><br />
Partition n<br />
Partition 2<br />
Partition 1<br />
Betriebssystem<br />
11 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.3.2 Dynamische Partitionierung<br />
• Länge, Anzahl und Anfangsadresse einer Partitionen ändern sich dynamisch.<br />
• Programm erhält genau so viel Speicher wie es benötigt und nicht mehr.<br />
• Interne Fragmentierung innerhalb einer Partition wird verhindert.<br />
• Aber ein neues Problem entsteht: externe Fragmentierung:<br />
- im Laufe der Zeit entstehen Löcher zwischen den Partitionen.<br />
- ein neues Programm kann eventuell nicht geladen werden,<br />
- aber Programm passt in keine Lücke, obschon insgesamt genügend Speicher vorhanden ist,<br />
Lösung: Heap Kompaktierung<br />
- Im Prinzip möglich, wenn die Partitionen relozierbar sind,<br />
- evtl. HW Unterstützung (Segmentdeskr., Basisregister, Virtueller Sp.)<br />
- unter Umständen viele Partitionen umkopieren und Adressen neu binden.<br />
12 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Beispiel für externe Fragmentierung:<br />
- Programm P4 kann erst geladen werden, nachdem P2 und P3 verschoben wurden.<br />
n<br />
0<br />
<strong>Hauptspeicher</strong><br />
Betriebssystem<br />
freier<br />
Speicher<br />
P1<br />
P2<br />
P3<br />
kompaktieren<br />
<strong>Hauptspeicher</strong><br />
Betriebssystem<br />
13 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
P4<br />
P1<br />
P2<br />
P3<br />
P4
4.3.3 Struktur einer Partition<br />
• Heap (Halde):<br />
- Explizite Allozierung zur Laufzeit,<br />
- für dynamische Datenstrukturen,<br />
- Ressourcen (Code, Puffer, ..).<br />
• Stack (Keller):<br />
- Parameter & lokale Variablen,<br />
- Rückkehradressen, Nesting ...<br />
- Hinweis: schwer identifizierbare Fehler,<br />
falls Stack und Heap sich<br />
überschneiden.<br />
• Globale Variablen:<br />
- Modulübergreifende Daten,<br />
• Code-Abschnitt:<br />
- eine oder mehrere Methoden,<br />
- meist schreibgeschützt,<br />
- ...<br />
high<br />
memory<br />
low<br />
frei<br />
globale Variablen<br />
Code<br />
Keller<br />
ESP<br />
Halde<br />
14 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.3.4 Format von Heapblöcken:<br />
• Ein Aufruf von new() ode malloc() liefert einen neuen Heapblock.<br />
• Header:<br />
- enthält Informationen für Speicherverwaltung und Freispeichersammlung:<br />
- Längenfelder, nächster Heapblock, Containergrösse, Anzahl Elemente,<br />
- Header normalerweise außerhalb des Nutzer-Blocks,<br />
- Flags: Locked, Read-Only, Free, Marked …<br />
- Typ: zB. Zeiger auf den Klassendeskriptor,<br />
• Auch ein nicht belegter Block braucht typischerweise einen Header.<br />
Heapblock<br />
Header Nutzerdaten und -code<br />
Heapblock<br />
Header leer<br />
Heapblock<br />
Header Nutzerdaten und -code<br />
15 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.3.5 Doppelköpfige Heapblöcke in Plurix<br />
• doppelköpfiges Format:<br />
- Trennung von Zeigern und Skalaren,<br />
- vereinfacht das Heap-Management.<br />
- Header in der Mitte des Blocks,<br />
- Zeiger zeigen auf den Header,<br />
- Zwei Längenfelder.<br />
• Rückwärtsverkettung:<br />
- Vereinfacht Garbage Collection,<br />
- Garbage hat leere Backchain,<br />
- BC vereinfacht Relozierung,<br />
- zirka 3 Backlinks in-line,<br />
- weitere Backlinks extern.<br />
• Stopper synchronisiert<br />
Heapwalk.<br />
• Winglets erlauben das Durchlaufen des<br />
Heaps in beiden Richtungen.<br />
Backlinks<br />
Zeiger<br />
Winglet<br />
Header<br />
Flags<br />
Winglet<br />
Skalare<br />
16 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.3.6 Handles & Masterzeiger:<br />
• Nur der Masterzeiger referenziert<br />
die Daten.<br />
• Ein Handle als Zeiger auf einen<br />
MasterZeiger.<br />
• Eventuell verweisen viele<br />
Handles auf einen MasterZeiger:<br />
• Verwendet in 16 Bit Windows<br />
3.x und älteren MacOS<br />
Versionen.<br />
aHandle<br />
bHandle<br />
cHandle<br />
MasterPtr<br />
• Vorteil: Der Speicherblock ist relozierbar, auch wenn nicht alle<br />
Referenzen/Handles bekannt sind und angepasst werden könnten,<br />
• Beim Dereferenzieren von Handles ist Vorsicht geboten, damit die<br />
Speicherverwaltung nicht unbeobachtet Verschiebungen vornimmt.<br />
relozierbarer Block<br />
17 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.4.1 Kellerrahmen („Stackframe“)<br />
4.4 Laufzeitkeller bzw. Stack<br />
• Welche Informationen werden für einen Prozeduraufruf im Keller<br />
festgehalten?<br />
• Aufgaben des Kellers:<br />
- Variablen im Keller, kein Code,<br />
- Funktionsresultat nur bei Funktionen.<br />
- Übergabe von Prozedurparametern,<br />
- Rücksprungadresse nach Abschluss,<br />
- Funktionsprinzip: „Last in First Out“.<br />
- Speichern von lokalen Variablen,<br />
- "Save area" für CPU-Register.<br />
• Zwischenresultate von Berechnungen.<br />
• Eventuell Parameter in Registern.<br />
Base<br />
pointer<br />
stack front<br />
Funktionsresultat<br />
Parameter<br />
Parameter<br />
Rücksprungadresse<br />
statische<br />
statische<br />
Verkettung<br />
Verkettung<br />
dynamische Verkettung<br />
Rücksprungadresse<br />
dynamische lokale Variablen<br />
Registeraufbewahrung<br />
Verkettung<br />
lokale Variablen<br />
temporäre<br />
Zwischenwerte<br />
stack front<br />
Registeraufbewahrung<br />
temporäre Zwischenwerte<br />
18 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
stack frame
4.4.2 Dynamische & statische Verkettung:<br />
• Dynamisch:<br />
- Bei Rücksprung aus einer Prozedur muss der alte Kellerrahmen wieder gefunden werden.<br />
• Statische Verkettung:<br />
- bei Sprachen, die geschachtelte Prozeduren erlauben.<br />
- innere Prozeduren haben Zugriff auf lokale Variablen von Äußeren.<br />
- diese Var. müssen im Stack adressierbar sein.<br />
Programm<br />
Proc B<br />
Proc C<br />
Proc A<br />
Globale Var.<br />
stack front<br />
19 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
Static chain<br />
A<br />
A<br />
B<br />
C<br />
C<br />
B<br />
C<br />
B<br />
dynamic chain
4.4.3 Displaytabelle<br />
• Alternative Implementierung zur statischen Verkettung.<br />
• Spiegelt verschachtelte Gültigkeitsbereiche des Quellprogramms wieder:<br />
- Compiler kennt aktuelle lexikalische Ebene, jedoch nicht Rekursionstiefe.<br />
- Displaytabelle liegt an definierter Speicherposition.<br />
- Globale Variablen auf lexikalischer Ebene #0.<br />
20<br />
Programm<br />
Globale<br />
LL #0<br />
Proc B<br />
Proc C<br />
Variablen<br />
A-Variablen<br />
B-Variablen<br />
LL #1<br />
LL #2<br />
LL #3<br />
Proc B<br />
C-Variablen<br />
Keller<br />
LL #4<br />
Displaytabelle<br />
Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.4.4 Kellerrahmen bei Intel x86<br />
• Keller wächst nach unten:<br />
- Ein Eintrag belegt 32-Bit.<br />
- 16-Bit mögl., aber nicht empfohlen.<br />
• EBP = Extended Base Pointer:<br />
- 32 Bit Register,<br />
- zeigt auf den akt. Kellerrahmen.<br />
• ESP = Extended Stack Pointer:<br />
- 32 Bit Register,<br />
- zeigt auf nächsten freien Stack-Eintrag.<br />
EBP<br />
ESP<br />
• Adressierung:<br />
- Parameter mit pos. Index relativ zu EBP.<br />
- lokale Variablen mit neg. Index relativ zu EBP.<br />
Parameter<br />
Rücksprungadresse<br />
altes EBP<br />
lokale Variablen<br />
unbelegt<br />
21 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.4.5 Aufrufkonventionen<br />
• Die Aufrufkonvention ist abhängig von der Programmiersprache.<br />
• Programmiersprache C zum Beispiel:<br />
- Param. werden von rechts nach links übergeben.<br />
- Die aufrufende Prozedur räumt den Keller auf.<br />
- Funktionsresultate werden in Registern zurückgegeben.<br />
int add(int x, int y)<br />
{<br />
int result;<br />
}<br />
...<br />
result = x + y;<br />
return result;<br />
add(5, 7)<br />
push EBP<br />
mov EBP,ESP<br />
sub ESP,4<br />
mov EAX,[EBP+8]<br />
add EAX,[EBP+12]<br />
mov [EBP-4],EAX<br />
mov EAX,[EBP-4]<br />
mov ESP,EBP<br />
pop EBP<br />
ret<br />
push 7<br />
push 5<br />
call add<br />
add ESP 8<br />
22 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Programmiersprache Pascal, zum Beispiel:<br />
- Funktionsresultate werden über den Keller zurückgegeben.<br />
- Parameter werden von links nach rechts übergeben.<br />
- Die aufgerufene Prozedur räumt den Keller auf.<br />
function add(x,y:integer):integer<br />
begin<br />
int result;<br />
result := x + y;<br />
add := result;<br />
end;<br />
...<br />
add(5, 7)<br />
push EBP<br />
mov EBP,ESP<br />
sub ESP,4<br />
mov EAX,[EBP+12]<br />
add EAX,[EBP+8]<br />
mov [EBP-4],EAX<br />
mov EAX,[EBP-4]<br />
mov [EBP+16],EAX<br />
mov ESP,EBP<br />
pop EBP<br />
ret 8<br />
push 0<br />
push 5<br />
push 7<br />
call add<br />
pop eax<br />
23 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Optimierung bei RISC-Prozessoren:<br />
- Eliminierung von Stackframes.<br />
- Parameterübergabe in Registern.<br />
- RISC Prozessoren haben viele Register,<br />
- und die Mögl., diese umzunummerieren.<br />
• Registerfenster ( -window):<br />
- Stack findet grösstenteils in den vielen Registern statt.<br />
- Relative Registeradressierung.<br />
#32=><br />
#31=><br />
96 Stack<br />
Register<br />
Output-Par.<br />
Lokale V.<br />
Input-Par.<br />
Verdeckte<br />
Register<br />
32 globale<br />
Register<br />
Call B<br />
#32=><br />
#31=><br />
Stack<br />
Lokale V.<br />
Input-Par.<br />
Verdeckte<br />
Register<br />
32 globale<br />
Register<br />
Return B<br />
#32=><br />
#31=><br />
Stack<br />
Rückgabe<br />
Lokale V.<br />
Input-Par.<br />
Verdeckte<br />
Register<br />
32 globale<br />
Register<br />
24 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
Aspekte einer Speicherverwaltung<br />
• Granularität der Speicherblöcke.<br />
• Belegungsdarstellung.<br />
4.5 Speicherverwaltung<br />
• Verschnitt (intern & externe Fragmentierung).<br />
• Auswahlstrategie (für freie Stücken).<br />
• Wiedereingliederung.<br />
4.5.1 Wiedereingliederung<br />
• Bei Freigabe eines Speicherblocks<br />
prüfen, ob Nachblöcke frei sind und<br />
gegebenenfalls zusammenfassen.<br />
• Hiermit entstehen wieder größere<br />
Blöcke.<br />
belegt frei belegt frei belegt<br />
belegt<br />
Freigabe<br />
frei belegt<br />
25 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.5.2 Belegungsdarstellungen<br />
Bitvektor:<br />
• Speicher wird in Einheiten fester Länge (z.B. 512 Byte oder 4 KB) unterteilt.<br />
• Jeder Einheit wird ein Bit in einem Bitvektor (Bitmap) zugeordnet.<br />
• Je kleiner die gewählte Einheit, desto größer ist der resultierende Bitvektor.<br />
• Je größer die Einheit, desto mehr interne Fragmentierung tritt auf.<br />
• Beispiel: 128 MB HS in 512 Byte Blöcke unterteilt, ergibt 32 KB Bitvektor.<br />
• Belegung eines Speicherbereichs erfordert das Durchsuchen des Bitvektors<br />
nach Nullbit-Folgen (sehr aufwendig).<br />
• Beispiel:<br />
0<br />
Prg. A Prg. B<br />
Prg. C<br />
Bitvektor/Bitmap<br />
0111110000111111110000001111111111110000 26 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
x
4.5.3 Freispeichertabelle etc.:<br />
• Speicher muss nicht in Einheiten<br />
fester Länge unterteilt werden.<br />
• freie Speicherblöcke in Tabelle.<br />
• sortiert nach Adresse/Größe.<br />
Freispeicherliste:<br />
• freie Speicherblöcke mit Zeiger verketten.<br />
• eventuell mehrere Listen:<br />
- verschied. Größen separat verketten,<br />
- pro Programm, ...<br />
• Optimierung:<br />
- Binärbaum für Zugriff,<br />
- Blockgröße als Schlüssel.<br />
0<br />
Prg.<br />
A<br />
Prg.<br />
A<br />
Prg.<br />
B<br />
Adr. Länge<br />
0 1<br />
6 4<br />
19 6<br />
39 4<br />
Prg.<br />
B<br />
Prg.<br />
C<br />
Länge Adr.<br />
1 0<br />
4 6<br />
4 19<br />
6 39<br />
Prg.<br />
C<br />
0 x<br />
27 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
x
Linearer Heap:<br />
• freie & belegte Blöcke sind dicht aneinander gereiht.<br />
• Verkettung erfolgt über das Längenfeld.<br />
• optimale Ordnung der Blöcke ist schwierig.<br />
• interne Zeiger sind überflüssig.<br />
• z.B. Mac OS & Plurix.<br />
Prg.<br />
A<br />
Prg.<br />
B<br />
Prg.<br />
C<br />
1 5 4 8 6 12 4<br />
0 x<br />
Länge eines Blocks<br />
28 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.5.4 Buddy-System:<br />
• Zwei gleichgroße benachbarte Blöcke nennt man Buddys („Kumpels“).<br />
• Speicher besteht aus 2 kmax Einheiten.<br />
• Speichervergabe in Blockgrößen 2 k .<br />
• Jeweils Liste für Blöcke der Größe<br />
2 k .<br />
• Variante in Linux-Kern verwendet.<br />
• Ablauf Anforderung:<br />
- Aufrunden auf nächste Zweierpotenz<br />
- Zugriff auf erstes freies Stück der Liste<br />
• Falls Liste leer (rekursiv):<br />
- Zugriff auf Liste der nächsten Größe.<br />
- Stück entfernen & halbieren.<br />
- Hintere Hälfte (=Buddy) in zugehörige<br />
Liste einhängen.<br />
2 4<br />
2 5<br />
2 6<br />
2 kmax<br />
• Kleiner Stücke entstehen aus (fortgesetzter) Halbierung größerer Stücke.<br />
• Benachbarte kleinere Stücke werden bei der Freigabe wieder vereinigt.<br />
29 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
...
• Ablauf der Speicherfreigabe:<br />
- Buddy bestimmen,<br />
- falls Buddy frei � Vereinigung .<br />
- falls Buddy belegt, freigewordenes Stück in die Liste einhängen.<br />
- Vorgang iterieren, bis Buddy belegt oder bei der max. Größe angekommen.<br />
• Vorteil: schnelles Verschmelzen freiwerdender Blöcke.<br />
• Nachteil: sowohl interne als auch externe Fragmentierung.<br />
Alloc 5 MB<br />
Alloc 3 MB<br />
Alloc 12 MB<br />
Free 3 MB<br />
Free 12 MB<br />
Free 5 MB<br />
2 M<br />
4 M<br />
8 M<br />
30 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
12 M<br />
16 M<br />
32 M
4.5.5 Auswahlstrategie<br />
• Kriterien: Verschnitt und Geschwindigkeit.<br />
• Gute Strategie kommt mit kleinem Heap aus.<br />
„First Fit“:<br />
• durchsucht die nach Adressen sortierte Liste immer ausgehend vom Anfang.<br />
• nimmt ersten freien Block der groß genug ist.<br />
• Zu grossen Block eventuell teilen, um ungebrauchten Platz zu sparen:<br />
- ohne Teilen � interne Fragmentierung<br />
- mit Teilen � externe Fragmentierung<br />
Vorteil: sehr schnelle Speicherzuteilung.<br />
Nachteil: Konzentration belegter Stücke am Anfang.<br />
31 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
„Next Fit“:<br />
• Freispeicherliste (sortiert nach Adresse) wird zyklisch durchlaufen.<br />
• Suche beginnt immer an der Stelle, wo letzte Belegung stattgefunden hat.<br />
• Eigenschaften wie „First Fit“, vermeidet aber die Konzentration von belegten<br />
Blk. am Anfang.<br />
0 x<br />
Stelle der letzten Belegung<br />
32 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
„Best Fit“:<br />
• sucht den Block, der am wenigsten Speicherverschnitt verursacht.<br />
• Unter Umständen nach Größe sortierte Freispeicherliste.<br />
• evtl. Binärbaum mit Größe als Schlüssel für Zugriff, um lineare Suche zu<br />
vermeiden.<br />
• Vorteil: keine Zerschneidung großer Stücke.<br />
• Nachteil: langsam; neigt bei Zerschneiden dazu sehr kleine unbrauchbare<br />
Stücke zu erzeugen.<br />
„Worst Fit“:<br />
• nimmt größten freien Block, damit noch brauchbare Stücke übrig bleiben.<br />
33 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.6.1 Overlay Technik<br />
4.6 Auslagern von Speicher<br />
• Notwendig, wenn das Programm größer als der <strong>Hauptspeicher</strong> ist.<br />
• Idee: Nicht benötigte Programmteile werden andere überlagert.<br />
• Realisierung: ein Wurzelsegment muss immer im HS sein.<br />
• Overlays werden vor dem Binden durch den Programmierer festgelegt.<br />
• Unterstützung von Programmoverlays durch:<br />
- Betriebssystem (z.B. MSDOS),<br />
- Compiler (z.B. Turbo Pascal � Units).<br />
• Problem: Der HS-Bedarf für die Daten<br />
ist schwer abschätzbar.<br />
• In Systemen mit virtuellem Speicher<br />
ist Overlaytechnik meist überflüssig.<br />
34<br />
<strong>Hauptspeicher</strong><br />
Overlay-<br />
Bereich<br />
Wurzelsegment<br />
Betriebssystem<br />
n<br />
0<br />
Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.6.2 Swapping<br />
• Swapping = Aus- und Wiedereinlagern auf Disk von ganzen Programmen<br />
oder Partitionen.<br />
• Notwendig im Multiprogrammbetrieb, falls nicht genügend <strong>Hauptspeicher</strong>.<br />
• Zeitaufwendig, da immer eine ganze Partition aus- und eingelagert wird.<br />
• Eventuell erfolgt später die Wiedereinlagerung an anderer Adresse.<br />
• Benötigt HW-Unterstützung.<br />
• Strategien:<br />
- Auslagern nicht rechenbereiter Programme<br />
- Prioritäten berücksichtigen.<br />
- Wurde in Windows 3.x eingesetzt.<br />
- Früher hat Unix auch Swapping eingesetzt:<br />
- zusätzlich zum Paging (virtueller Speicher),<br />
- wenn kein Proz. mehr genügend Speicher hat.<br />
- also nur in extremen Wettbewebsituationen.<br />
35 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
= Garbage Collection (GC)<br />
4.7 Automatische Freispeichersammlung<br />
• Explizite Rückgabe durch Programmierer ist fehleranfällig & mühsam:<br />
- Abbau komplexer Strukturen oft schwierig.<br />
- Destruktoren in OO Sprachen (z.B. C++) löschen u. U. weitere Objekte.<br />
- wird ein Objekt zu früh freigegeben => Dangling Pointers (baumelnde).<br />
- wird vergessen Speicher freizugeben => Memory Leaks (Speicher Leck).<br />
• Lösung: automatische Freispeichersammlung:<br />
- nicht mehr adressierbare Blöcke automatisch identifizieren und freigeben.<br />
- Entweder für ein einmzelnes Programm oder systemweit,<br />
- Beispiele: Java, .NET, Oberon, ...<br />
• Voraussetzungen:<br />
- sämtliche Referenzen auf einen Speicherblock müssen auffindbar sein.<br />
- typsichere Sprache dringend empfohlen.<br />
• Aufrufen der GC:<br />
- Implizit durch das OS,<br />
- explizit durch den Programmierer,<br />
- oder bei Bedarf, wenn der Speicher knapp wird.<br />
36 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.1 Grundprinzip der Freispeichersammlung<br />
Collector: sammelt Garbage.<br />
Mutator: alle Programme, welche den Heap ändern (mutieren).<br />
1. Phase: Garbage Detection<br />
Erkennung von referenzierbaren und nicht mehr referenzierbaren Objekten.<br />
2. Phase: Garbage Reclamation<br />
Freigabe des Speichers von nicht mehr referenzierbaren Objekten.<br />
• Nicht mehr referenzierbare Objekte:<br />
- Es existiert kein Pfad zwischen dem Objekt und einer Zustandsvariablen.<br />
• Zustandsvariablen (Root-Set):<br />
- Klassenvariablen,<br />
- globale Variablen,<br />
- lokale & Modulvariablen.<br />
• Zirkulärer Garbage ist unangenehm:<br />
- jedes Objekte noch referenziert,<br />
- aber nicht vom Root-Set aus erreichbar.<br />
- Zyklus muss erkannt & aufgebrochen werden.<br />
37 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.2 Compilerunterstützung<br />
• Referenzen innerhalb eines Blocks<br />
müssen identifizierbar sein.<br />
• Benötigt wird:<br />
- Offset und Typ der globalen<br />
X ^Y<br />
Zeigervariablen, A ^X<br />
- Offset und Typ der lokalen<br />
^Y<br />
Zeigervariablen,<br />
Global<br />
- Identifikation von Kellerrahmen,<br />
Stack<br />
- Zeigerfelder in dynamisch allozierten<br />
Records bzw. Instanzen.<br />
• Vereinfachung durch<br />
doppelköpfiges Layout für<br />
Speicherblöcke (siehe 4.3.3).<br />
B<br />
Global Frame<br />
Proc-A Frame<br />
Proc-B Frame<br />
Record-X Type<br />
Record-Y Type<br />
…<br />
X<br />
Y<br />
Y<br />
^Y<br />
^X<br />
^X<br />
^Y<br />
^Y<br />
Heap<br />
Tabelle<br />
– – – – – –^Y – –<br />
– –^X – – – – – –<br />
–^Y – – – – – – –<br />
– – – –^Y – – – –<br />
– ^X – – – –^Y – –<br />
38 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.3 Mark & Sweep<br />
• Der Sammelalgorithmus markiert alle noch erreichbaren Blöcke im Heap:<br />
• Ausgehend von einer Menge von Wurzel-zeigern werden alle noch aktiven<br />
(live) Zeiger und deren Objekte gefunden.<br />
• Nicht markierte Blöcke sind dann frei (bzw. Garbage) und können<br />
eingesammelt werden.<br />
• Erforderliche Symbol- und Typentabelle wird vom Compiler erzeugt.<br />
• Die Markierungsphase muss in einem Stück zu Ende laufen.<br />
� Manipulation an Zeigern durch den Mutator würden GC verwirren.<br />
•<br />
Garbage<br />
39 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
für jede Zustandsvariable s:<br />
Markiere(s);<br />
für jedes Objekt o, für das gilt o.mark = 0 :<br />
Speicherfreigabe(o)<br />
Markiere(s):<br />
wenn s.mark = 1 dann beende Prozedur<br />
s.mark := 1;<br />
für jedes von s referenzierteObjekt o:<br />
Markiere(o)<br />
Vorteil: Zyklen werden erkannt.<br />
- Funktion zum Markieren beinhaltet unter Umständen tiefe Rekursion<br />
es ist viel Speicherplatz im Keller notwendig,<br />
- Alternativ mit Zeigerrotation arbeiten.<br />
• Das Verschieben von Blöcken zur Gewinnung von größeren Bereichen<br />
(Kompaktieren) ist möglich aber mühsam.<br />
40 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.4 Inkrementelles Mark & Sweep<br />
• Nebenläufiges Mark & Sweep nach einer Idee von E. W. Dijkstra, 1978.<br />
• Objekte werden mit drei Farben markiert:<br />
- blau: Objekt wurde komplett untersucht.<br />
- rot: Objekt wurde noch nicht inspiziert.<br />
- grün: Objekt wurde bereits besucht, aber noch nicht alle seine Nachfolger.<br />
• Alle besuchten Objekte werden blau markiert und alle von hier aus<br />
erreichbaren Obj. grün.<br />
• Der Algorithmus terminiert, wenn keine grünen Objekte mehr existieren.<br />
• Der Collector schiebt eine Front grüner Objekte vor sich her:<br />
• Es werden u.U. nicht alle<br />
Garbage Objekte in einem<br />
Durchlauf eingesammelt.<br />
41<br />
Rootset<br />
bereits untersucht<br />
wird gerade<br />
untersucht<br />
noch nicht<br />
erreicht<br />
Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Bedingung: bereits untersuchte Objekte, dürfen keine Zeiger auf noch nicht<br />
untersuchte Objekte beinhalten:<br />
• Erfolgt eine Zuweisung einer Referenz von einem blauen auf ein rotes Objekt,<br />
so muss das Letztere grün eingefärbt werden.<br />
� Zeigerzuweisungen überwachen<br />
bereits untersucht<br />
wird gerade<br />
untersucht<br />
muss grün<br />
eingefärbt werden<br />
noch nicht<br />
erreicht<br />
Nachteil: Überwachung von Zeigerzuweisungen zur Laufzeit ist teuer.<br />
• Compiler fügt z.B. für jede Zeigerzuweisung einen Aufruf an eine Laufzeitroutine<br />
ein.<br />
42 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.5 Kopierende Freispeichersammlung<br />
• Erste Implementierung Marvin Minsky, 1963.<br />
• Halde in zwei Regionen alt & neu unterteilt.<br />
• Alle vom Rootset aus erreichbaren Objekte werden rekursiv in die neue<br />
Region kopiert.<br />
• Garbage verbleibt in alter Region.<br />
• Beim nächsten GC-Aufruf tauschen<br />
die alte und neue Region ihre Rollen.<br />
• Vorteil:<br />
alte Region<br />
- Heap wird automatisch kompaktifiziert. neue Region<br />
- Zyklen werden eliminiert.<br />
Nachteile:<br />
- Es ist teuer, viele kleine Objekte zu kopieren.<br />
- logischer Adressraum wird halbiert.<br />
- Kopieren muss atomar erfolgen.<br />
43 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.6 Inkrementeller Copying Collector<br />
• Bei jedem Aufruf der GC wird<br />
nur eine vorgegebene Anzahl<br />
von Objekten kopiert.<br />
• Es muss nicht für längere Zeit<br />
die ganze Verarbeitung<br />
gestoppt werden.<br />
Iterative Lösung nach Cheney:<br />
• Neue Region wird fortlaufend<br />
gefüllt � Queue.<br />
A<br />
C<br />
alte Region<br />
A=Root<br />
B<br />
D A‘<br />
• scan-Zeiger: Objekte bis hier sind komplett abgearbeitet.<br />
neue Region<br />
Beim Scannen von A‘<br />
wird D kopiert<br />
D‘<br />
scan free<br />
• free-Zeiger: Objekte zwischen scan- und free-Zeiger sind kopiert, aber haben<br />
noch Zeiger in die alte Region.<br />
• Kopierte alte Objekte verweisen auf Ihre Kopie (z.B. A = Root-Variable).<br />
44 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Der Algorithmus terminiert, wenn scan-Zeiger auf free-Zeiger trifft.<br />
• Bedingung:<br />
- komplett abgearbeitete Objekte, dürfen nicht auf noch nicht kopierte Objekte verweisen.<br />
• Erfolgt eine derartige Zuweisung, so muss das referenzierte Objekt sofort<br />
kopiert werden.<br />
� Zeigerzuweisungen überwachen<br />
• z.B. der Compiler fügt für jede Zeigerzuweisung den Aufruf einer Laufzeitroutine<br />
ein.<br />
• Nachteil:<br />
- Überwachung von Zeigerzuweisungen ist teuer.<br />
45 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
4.7.7 Reference Counting<br />
• Jeder Speicherblock wird durch einen versteckten Referenzzähler erweitert<br />
und speichert die Anzahl der Referenzen auf ein Objekt<br />
• Ein Objekt ist Garbage, wenn der Referenzzähler null ist.<br />
• Zeigerzuweisung über Laufzeitfunktion:<br />
- In der Laufzeitroutine erfolgt Zeigerzuweisung und Inkrementierung des Referenzzählers.<br />
- Bei Zuweisung von „null“ wird der Referenzzähler erniedrigt.<br />
• Bei sehr vielen Referenzen auf ein Objekt soll der Zähler "kleben" bleiben.<br />
• Vorteile:<br />
- inkrementelle Freispeichersammlung möglich,<br />
- Garbage wird sofort freigegeben.<br />
- einfach implementierbar.<br />
• Nachteile:<br />
- Zyklen werden nicht erkannt.<br />
- Zeigerverwaltung erforderrt den<br />
Aufruf einer Laufzeitroutine<br />
1<br />
1<br />
2<br />
1<br />
1<br />
1<br />
1<br />
1<br />
Garbage<br />
46 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess<br />
1
4.7.8 Backchain<br />
• Ursprünglich in Plurix verwendet.<br />
• Jeder Speicherblock führt eine<br />
Backchain, eine Liste der Referenzen,<br />
welche auf ihn zeigen.<br />
• Im Falle einer Allozierung („new“) wird<br />
der zugeordnete Zeiger in die Liste<br />
eingetragen.<br />
• Wird eine Zeigervariable freigegeben,<br />
wird sie aus der Backchain entfernt.<br />
Backchain<br />
Referenzen<br />
Heap Objekt<br />
• Wird ein gültiger Zeigerinhalt einer anderen Referenz zugewiesen (assigned),<br />
so wird auch dieser Zeiger eingetragen.<br />
• Freispeichersammlung sammelt nun alle Blöcke mit leerer Backchain ein.<br />
• Im Prinzip eine Abwandlung der Reference Counting Technik.<br />
47 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess
• Heap-Kompaktierung:<br />
- Dynamische Relozierung von allozierten Blöcken.<br />
- Zeiger mit Hilfe der Backchain anpassen.<br />
• Vorteil:<br />
- inkrementelles Sammeln möglich.<br />
- Heap kann kompaktifiziert werden.<br />
- Zeiger einfach & eindeutig<br />
identifizierbar.<br />
• Nachteil:<br />
Objekt<br />
- Zyklen werden nicht erkannt.<br />
- Referenzen sind doppelt so groß.<br />
- Austragen von Zeigern teuer � O(n).<br />
- Zeigerverwaltung kostet Aufruf von Laufzeitfkt.<br />
• Backpacks als Weiterentwicklung der Backchain:<br />
- Mehrzahl der Backlinks werden in-line untergebracht,<br />
- Weitere Backlinks liegen in separaten Heap-Blöcken,<br />
- Progressiv wachsende Containergrösse für die Backpacks.<br />
Backpacks<br />
Backlinks<br />
48 Betriebssysteme Sommer 2004, ©VS Informatik, <strong>Universität</strong> <strong>Ulm</strong>, P. Schulthess