29.10.2012 Aufrufe

Hauptspeicher - Universität Ulm

Hauptspeicher - Universität Ulm

Hauptspeicher - Universität Ulm

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

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

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

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!