Übungen Betriebssysteme (BS)

U4 – Speicherverwaltung

Alwin Berger

🚀 by Decker

Agenda

  • Arbeitsspeicherverwaltung
    • Paging und Segmentierung
  • Ersetzungsalgorithmen
    • LFU-Algorithmus
    • LRU-Algorithmus
  • Dynamische Speicherverwaltung in C mit malloc und free
  • Platzierungsstrategie Next Fit

Arbeitsspeicher

images/U4/paging/paging_0001.svg

Arbeitsspeicher

images/U4/paging/paging_0002.svg

Speicherlandkarten

  • Die Menge aller Adressen der Speicherzellen (die einem Prozess zur Verfügung stehen) wird als Adressraum des Prozesses bezeichnet
  • Die skizzenhafte Darstellung eines Adressraumes als Speicherlandkarte (engl. memory map)
Monolithisch / Defragmentiert: Zusammenhängend
Fragmentiert: Nicht zusammenhängend

Virtuelle Adressen (Motivation)

images/U4/U4-4.svg

Virtuelle Adressen (Motivation)

images/U4/U4-5.svg

Virtuelle Adressen (Motivation)

images/U4/U4-6.svg

Paging (Motivation)

images/U4/U4-7.svg

Paging

images/U4/U4-8.svg

Paging

images/U4/U4-9.svg

Speicherverwaltungseinheit (MMU)

images/U4/U4-10.svg

Speicherarchitektur ohne MMU

images/U4/U4-11.svg

Speicherarchitektur mit MMU

images/U4/U4-12.svg

Holen der Kachelnummer (Falls vorhanden)

images/U4/U4-13.svg

Sonderfall: Kachelnummer nicht vorhanden

images/U4/U4-14.svg

Zusammensetzen der physikalischen Adresse

images/U4/U4-15.svg

Segmentierung

images/U4/U4-16.svg

Segmentierung

images/U4/U4-17.svg

Segmentierung

images/U4/U4-18.svg

Holen der Segmentnummer (Falls vorhanden)

images/U4/U4-19.svg

Zusammensetzen der physikalischen Adresse

images/U4/U4-20.svg

Präsenzaufgabe: Segmentierung

images/U4/U4-21.svg

Präsenzaufgabe: Segmentierung

images/U4/U4-22.svg

Präsenzaufgabe: Segmentierung

images/U4/U4-23.svg

Präsenzaufgabe: Segmentierung mit Paging

images/U4/U4-25.svg

Ersetzungsalgorithmen (Motivation)

images/U4/U4-39.svg

Ersetzungsalgorithmen (Motivation)

images/U4/U4-40.svg

Präsenzaufgabe: LFU-Algorithmus

images/U4/U4-71.svg

LFU-Algorithmus

images/U4/U4-72.svg

LFU-Algorithmus

images/U4/U4-73.svg

LFU-Algorithmus

images/U4/U4-74.svg

LFU-Algorithmus

images/U4/U4-75.svg

LFU-Algorithmus

images/U4/U4-76.svg

LFU-Algorithmus

images/U4/U4-77.svg

LFU-Algorithmus

images/U4/U4-78.svg

LFU-Algorithmus

images/U4/U4-79.svg

LFU-Algorithmus

images/U4/U4-80.svg

LFU-Algorithmus

images/U4/U4-81.svg

LFU-Algorithmus

images/U4/U4-82.svg

LFU-Algorithmus

images/U4/U4-83.svg

LFU-Algorithmus

images/U4/U4-84.svg

LFU-Algorithmus

images/U4/U4-85.svg

Präsenzaufgabe: LRU-Algorithmus

images/U4/U4-86.svg

LRU-Algorithmus

images/U4/U4-87.svg

LRU-Algorithmus

images/U4/U4-88.svg

LRU-Algorithmus

images/U4/U4-89.svg

LRU-Algorithmus

images/U4/U4-90.svg

LRU-Algorithmus

images/U4/U4-91.svg

LRU-Algorithmus

images/U4/U4-92.svg

LRU-Algorithmus

images/U4/U4-93.svg

LRU-Algorithmus

images/U4/U4-94.svg

LRU-Algorithmus

images/U4/U4-95.svg

LRU-Algorithmus

images/U4/U4-96.svg

LRU-Algorithmus

images/U4/U4-97.svg

LRU-Algorithmus

images/U4/U4-98.svg

LRU-Algorithmus

images/U4/U4-99.svg

LRU-Algorithmus

images/U4/U4-100.svg

Dynamische Speicherverwaltung

images/U4/dyn/dyn_0001.svg

Dynamische Speicherverwaltung in C

  • Standardbibliotheksfunktion zur Allokation von Speicher:
void* malloc(size_t size)
  • Reserviert zur Laufzeit Speicher auf dem Heap
  • Das Argument size legt die Größe des zu reservierenden Bereichs in Bytes fest
  • Rückgabewerte:
    • ≠ NULL, wenn Allokation erfolgreich -> Rückgabewert ist Adresse
    • = NULL, wenn ein Fehler aufgetreten ist

Speicherplatz freigeben

  • Gegenstück zu malloc:
void* free(void *ptr)
  • Gibt Speicher an Adresse ptr wieder frei
  • Speicher darf nur einmal freigegeben werden

Array im Heap

int* first_n_squares(unsigned n) {
	int* array;
	array = malloc(n * sizeof(*array)); // ❶ malloc
	if (array == NULL) { // ❷ Fehlerbehandlung
		perror("malloc");
		exit(EXIT_FAILURE);
	}
	for (int i = 0; i < n; ++i) {
		array[i] = i * i;
	}
	return array;
}

int main(void) {
	int* ptr;
	ptr = first_n_squares(200);
	printf("10*10 = %d\n", ptr[10]) ;
	free(ptr); // ❸ free
	return 0;
}

Casting von Zeigern

  • Zeiger lassen sich beliebig in andere Zeigertypen umwandeln.
    • Ihr müsst sicherstellen, dass am Zielort genug Speicher reserviert ist.
  • Beispiel: Wie schreibt man den Int-Wert 0x12345678 in einen Bereich der Größe 42?
char *x = malloc(42);
  • Der Zeiger x wird gecastet:
    • x ist ein Zeiger auf ein char
    • ( int* )(x) castet x zu einen Zeiger auf ein int
    • Wie gewohnt dereferenzieren:
    *((int*)(x)) = 0x12345678;

Zeiger als einfache Zahl nutzen

  • Zeigervariablen lassen sich durch Typumwandlung als Zahl Zweck-entfremden oder umgekehrt
    • Problem: sizeof(void*) ist plattformabhängig (32b vs. 64b CPUs)
    • Umwandlungen zwischen verschieden großen Werten können zu Fehlern führen.
  • intptr_t(3) und uintptr_t haben immer die richtige Größe.
void* thread_function(void* arg) {
	intptr_t number = (intptr_t)arg; // 9223372036854775807
	int wrong = (int)arg; // -1
	// ...
}
int main() {
	pthread_t thread_id;
	pthread_create(&thread_id, NULL, thread_function, (void*)INTPTR_MAX);
	pthread_join(thread_id, NULL);
	return 0;
}

Speicherplatzierungsstrategien

  • Platzierung und Fragmentierung finden sich auf verschiedenen Ebenen wieder
    • Betriebssystem, Heap in Prozess, Dateien auf Festplatten und mehr
  • Fokus der heutigen Übung: dynamische Allokation auf dem Heap
    • Besprechung “Next Fit” und “Best Fit”

Speicherplatzierungsstrategie ‘Next Fit’

  • Sucht nächste passende Lücke im Speicher
  • Merkt sich Position der letzten Allokation, setzt Suche bei nächster Anfrage dort fort
  • Schnelle Platzierungsstrategie die sich besonders für sehr kleine Blöcke gut eignet

Allokation

  • Metadaten pro Block (Chunk)
    • Status des Blocks: frei oder belegt
    • Länge des Blocks; falls 0, ist der Status irrelevant
  • Anfänglich können Daten hintereinander in den Speicher gelegt werden

Ausgangszustand

images/U4/dyn/dyn_0003.svg

Allokation eines Blockes A der Länge 14

images/U4/dyn/dyn_0004.svg

Allokation eines Blockes B der Länge 4

images/U4/dyn/dyn_0005.svg

Allokation eines Blockes C der Länge 8

images/U4/dyn/dyn_0006.svg

Allokation eines Blockes D der Länge 4

images/U4/dyn/dyn_0007.svg

Reallokation

  • Blöcke können realloziert werden, indem der Status entsprechend angepasst wird
  • Vergrößern ist nur möglich, wenn hinter dem Block eine entsprechend große Lücke frei ist

Blöcke vor einer Reallokation

images/U4/dyn/dyn_0008.svg

Blöcke vor nach der Reallokation von 𝐴, 𝐶, 𝐷

images/U4/dyn/dyn_0009.svg

Suche nach entsprechend großer Lücke

  • Falls Bereich reserviert, um die Länge des reservierten Bereichs weiter springen
  • Wenn Ende des Speichers erreicht, dann Vorne fortsetzen

Allokation eines Blockes E der Länge 1

images/U4/dyn/dyn_0010.svg

Freigabe

  • Markiere Startblock als frei
  • Angrenzende Bereich überprüfen
    • Bereich davor frei? → Verschmelzen
    • Bereich dahinter frei? → Verschmelzen

Vor der Freigabe von E und C

images/U4/dyn/dyn_0011.svg

Freigabe von E

images/U4/dyn/dyn_0012.svg

Freigabe von C

images/U4/dyn/dyn_0013.svg

Verschmelzen

images/U4/dyn/dyn_0014.svg

Speicherplatzierungsstrategie ‘Best Fit’

  • Sucht die am besten passende Lücke im Speicher
  • Aufwendigere Strategie die aber für größere Blöcke sehr gute Ergebnisse liefert

Kombinierte Strategien

  • Kleine Allokationen schnell mit “Next Fit” ausführen, große mit “Best Fit”
images/U4/dyn/dyn_0002.svg

Zusatzinhalte

Übersetzungspuffer (TLB)

images/U4/U4-26.svg

Übersetzungspuffer (TLB)

images/U4/U4-27.svg

Präsenzaufgabe: Übersetzungspuffer (TLB)

images/U4/U4-28.svg

Präsenzaufgabe: Übersetzungspuffer (TLB)

images/U4/U4-29.svg

Präsenzaufgabe: Übersetzungspuffer (TLB)

images/U4/U4-30.svg

Präsenzaufgabe: Übersetzungspuffer (TLB)

images/U4/U4-31.svg

Präsenzaufgabe: Übersetzungspuffer (TLB)

images/U4/U4-32.svg

Präsenzaufgabe: Übersetzungspuffer (TLB)

images/U4/U4-33.svg

Direkte Abbildung mit TLB (Ein Index pro Tag)

images/U4/U4-34.svg

Mengenassoziativer Speicher (𝑗 Tags pro Index)

images/U4/U4-35.svg

Vollassoziativer Speicher (Ohne Index)

images/U4/U4-36.svg

Implementierung: 2-Weg assoziativ-Speicher

images/U4/U4-37.svg

Implementierung: Zusammenfassung

images/U4/U4-38.svg

Implementierung des LRU-Algorithmus

images/U4/U4-102.svg

Implementierung des LRU-Algorithmus

images/U4/U4-103.svg

Implementierung des LRU-Algorithmus

images/U4/U4-104.svg

Implementierung des LRU-Algorithmus

images/U4/U4-105.svg

Implementierung des LRU-Algorithmus

images/U4/U4-106.svg

Implementierung des LRU-Algorithmus

images/U4/U4-107.svg

Implementierung des LRU-Algorithmus

images/U4/U4-108.svg

Implementierung des LRU-Algorithmus

images/U4/U4-109.svg

Implementierung des LRU-Algorithmus

images/U4/U4-110.svg

Präsenzaufgabe: Aufrufen von Kacheln

images/U4/U4-111.svg

Präsenzaufgabe: Aufrufen von Kacheln

images/U4/U4-112.svg

Präsenzaufgabe: Aufrufen von Kacheln

images/U4/U4-113.svg

Präsenzaufgabe: Welche Kachel ist die älteste?

images/U4/U4-114.svg

Präsenzaufgabe: Welche Kachel ist die älteste?

images/U4/U4-115.svg

Präsenzaufgabe: Welche Kachel ist die älteste?

images/U4/U4-116.svg

Von-Neumann Memory-Wall

images/U4/U4-119.svg

Von-Neumann Memory-Wall

images/U4/U4-118.svg

Von-Neumann Memory-Wall

images/U4/U4-120.svg

Flaschenhals

images/U4/U4-121.svg

Caches

images/U4/U4-122.svg

Reale und virtuelle Caches

images/U4/U4-123.svg

Cache und MMU in historischen Systemen

images/U4/U4-124.svg

Implementierung von Caches

images/U4/U4-125.svg

Seitenflattern

images/U4/U4-126.svg

Kontextwechsel

images/U4/U4-127.svg

Notizbuchspeicher

images/U4/U4-128.svg

Notizbuchspeicher

images/U4/U4-129.svg