C TutoriumC Tutorium – Memory Management – – Memory Management –
Knut Stolze
2
AgendaAgenda
Einführung in die SpeicherverwaltungStack vs. HeapMallocFreeSizeofTipps/Hinweise
3
SpeicherverwaltungSpeicherverwaltung
Speicher (RAM) ist (meist) liniar und ein zusammenhängender Bereich– Muss unterteilt/strukturiert werden
Alle Informationen (Daten und Programme) müssen im Hauptspeicher abgelegt werden
Virtualisierung von Speicher– Erweiterung des physisch vorhandenen Hauptspeichers
um Paging/Swap Space– Betriebssystem kümmert sich um Paging/Swapping
4
Speicherverwaltung (2)Speicherverwaltung (2)
Programme können parallel laufen– Jedes Programm ist unabhängig von anderen– Speicher muss zugeteilt/reserviert werden– Jede Variable in einem Programm muss in
einem zuvor reservierten Speicherbereich abgelegt werden!
Prozess 1 Prozess 3 Prozess 3
Gesamter (virtueller) Speicher
5
Stack vs. HeapStack vs. Heap
Speicher, der einem Programminsgesamt zur Verfügung steht
Heap Stack
Stack-Pointer
6
Stack vs. Heap (2)Stack vs. Heap (2)
Stack und Heap teilen sich gesamten zur Verfügung stehenden Speicher– Pro Prozess
Heap: dynamisch benötigter SpeicherStack: statisch verwendeter Speicher
7
StackStack Für alle statischen Informationen während des
Programmablaufs– Wird zur Laufzeit allokiert – nicht beim Starten!
Aufrufinformationen– Welche Funktion wurde von wo aufgerufen– Parameter der aufgerufenen Funktion– Rücksprungadresse
Statische Variablen in der Funktion– Z.B. int a[50]
Genügend Speicher für 50 “int” Werte– Werden automatisch beim Verlassen der Funktion aufgeräumt, d.h.
der Speicher wird wieder freigegeben
8
Stack (2)Stack (2)Andere Programmiersprachen
– C++: Destruktor von Objekten wird aufgerufen und Speicher wird freigegeben
– Java: Reference count von Objekten auf dem Stack wird reduziert garbage collector räumt auf
Allokation auf dem Stack ist schneller/performanter als vom Heap– Heap kann Fragmentieren; Stack nicht
9
HeapHeap
Für dynamisch allokierten Speicher Wird vom Betriebssystem (OS) verwaltet
– Funktion “malloc” fordert Speicherblock an Passender Block muss gesucht, reserviert und zurückgegeben
werden– Funktion “free” gibt zuvor angeforderten Speicherblock
wieder frei OS verwaltet alle angeforderten Speicherblöcke Speicher des Heaps kann fragmentieren
10
Ulimit (Unix)Ulimit (Unix) Legt Maximum von Resourcen für einen Prozess fest:
– Maximal nutzbarer Speicherbereich (virtuell)– Größe des Stacks– Größe von “core” Dateien– Größe des “data segment” eines Prozesses– Größe von Dateien, die ein Prozess anlegen kann– Größe des ge”pin”ten SpeicherbereichsAnzahl der
geöffneten Dateien– Blockgröße bei Pipes– Anzahl der Prozesse eines Nutzers– CPU-Zeit
11
MallocMalloc
Fordere einen Speicherblock vom Heap anptr = malloc(size);– “ptr” ist ein Zeiger auf den Beginn des
Speicherblocks Ein Zeiger ist eine Adresse im Hauptspeicher
– “size” ist die Größe des Blocks in Anzahl von Bytes
Speicherblock
Heap im Hauptspeicher
ptr(0x01234567)
12
Malloc (2)Malloc (2) Gibt Zeiger vom Typ “void *” zurück
– Typ der Werte, die im Speicherblock hinterlegt werden sollen ist “malloc” nicht bekannt
– Typ muss mittels Cast umgewandelt werdenint *ptr = NULL;ptr = (int *)malloc(size);
Es darf nicht ausserhalb des allokierten Speicherblocks zugegriffen werden– Speicher könnte anderen Prozessen oder anderen
Datenstrukturen des gleichen Prozesses gehören
13
Malloc (3)Malloc (3)Ähnliche Systemfunktionen:
– callocAndere Programmiersprachen verwenden
ähnliche Operatoren, die Typisierung gleich mitliefern, d.h. der Cast wird intern gleich mit erledigt:– C++: Class *object = new Class();– Java: Class object = new Class();
14
Grundlagen vonGrundlagen vonZeiger-ArithmetikZeiger-Arithmetik
Ergebnis von “malloc” zeigt auf 1 Element des spezifizierten Datentypsptr = (int *)malloc(size);– “ptr” zeigt auf ein “int”-Wert
Zeigerarithmetik arbeitet grundsätzlich auf dem zu Grunde liegenden Datentyp– “ptr = ptr + 1;” lässt den Zeiger auf den nächsten “int”-
Wert zeigen (und nicht auf das zweite Byte)
15
FreeFree Angeforderte Speicherblöcke müssen wieder
freigegeben werdenfree(ptr);– Sobald nicht mehr gebraucht– Geschieht automatisch beim Programmende
Zeiger auf Speicherblock darf bis zum “free” nicht verloren gehen!
Ein Block kann nur genau 1x freigegeben werden– Mehrfache “free” Operationen könnten einen falschen Block
freigeben– Danach darf Block nicht mehr verwendet werden
16
Free (2)Free (2)
Freigegebener Block (oder ein Teil davon) kann beim nächsten “malloc” wieder vergeben werden
Andere Programmiersprachen verwenden intern auch “free”:– C++: delete-Operator– Java: garbage collection
17
Sizeof OperatorSizeof Operator Anzahl der Bytes von Datentypen kann von
Plattform zu Plattform variieren– Z.B. unterschiedliche Größen von “int” Werten (32 vs.
64 Bit Prozessoren)– Unterschiedliche Optimierungsstrategien der Compiler– Unterschiedliche Mächtigkeit/Performance der
Adressierungsbefehle des Prozessors– Zugriff auf Speicheradressen, die ein Vielfaches von 4
Bytes sind, oft schneller als Adressierung einzelner Bytes
18
Sizeof Operator (2)Sizeof Operator (2)
Padding-Bytes können vom Compiler eingeschoben werden
Genaue Größe von Strukturen oft nicht bekannt oder soll nicht hart-verdrahtet werden (Portabilität)
19
Sizeof Operator (3)Sizeof Operator (3) “sizeof” berechnet Größe eines Wertes oder eines
Datentypssize = sizeof(int);size = sizeof(struct myStruct);size = sizeof myValue;– Anzahl an Bytes, die die physisch Repräsentation im
Speicher benötigtptr = (int *)malloc(N * sizeof(int));
Kann bereits zur Übersetzungszeit errechnet werden und belastet somit nicht die Laufzeit
20
ReallocRealloc
Vorgrößern von Speicherblöcken ist nicht direkt möglich– Andere Speicherblöcke können physisch im Speicher
direkt dahinter liegenint *ptr = NULL;int *biggerPtr = NULL;ptr = (int *)malloc(orig_size);…biggerPtr = (int *)realloc(ptr, new_size);
21
Memset, memcpy, memmoveMemset, memcpy, memmove Angeforderte Speicherblöcke (malloc) sollten
immer initialisiert werdenmemset(ptr, 0x00, size);– Bei sicherheitskritischen Anwendung ist ein “Leeren”
vor dem Freigeben auch oft ratsam! Kopieren zwischen überlappungsfreien
Speicherblöckenmemcpy(destination, source, size);
Kopieren zwischen überlappenden Speicherblöckenmemmove(destination, source, size);
22
Richtlinien & TippsRichtlinien & TippsSpeicherallokation kann fehl schlagen!!
– Ergebnis ist dann NULL-Zeiger– Ergebnis muss immer überprüft werden
Speicherblock nach “free” nicht weiter verwenden– Am besten Zeiger auf NULL setzen:free(ptr);ptr = NULL
23
Richtlinien & Tipps (2)Richtlinien & Tipps (2)Alle Variablen sofort bei der Deklaration
initialisierenchar *str = NULL;int counter = 0;
str = (char *)malloc(strlen(orig_str)+1);if (!str) { … }memset(str, 0x00, strlen(orig_str)+1);
24
Potientielle ProblemePotientielle Probleme
Keine gute Kontrolle über Speicher– Keine Gruppierung von Speicher– Keine Fehlermeldung beim falschen Freigeben
Programm stürzt eventuell ab; vielleicht auch an ganz anderer Stelle
Buffer Overflow verhindern – Zugriff ausserhalb des aktuellen Speicherblocks– Oft keine/unzureichende Prüfung von Überläufen– Kann sich oft zu Sicherheitsproblemen ausweiten
25
Potentielle Probleme (2)Potentielle Probleme (2)
Memory Leaks – angeforderter Speicher wird nie freigegeben– Zeiger auf Speicherblock ist verloren gegangen
Funktionen dürfen keinen Zeiger in den Stack zurückgeben– Informationen auf dem Stack sind beim Verlassen der
Funktion nicht mehr gültig “free” auf Objekt auf dem Stack ist nicht zulässig
– Führt meist zum Absturz des Programms