ptr

Werbung
C Tutorium
– Memory Management –
Knut Stolze
Agenda

Einführung in die Speicherverwaltung
 Stack vs. Heap
 Malloc
 Free
 Sizeof
 Tipps/Hinweise
2
Speicherverwaltung

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
3
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
4
Stack vs. Heap
Stack-Pointer
Heap
Stack
Speicher, der einem Programm
insgesamt zur Verfügung steht
5
Stack vs. Heap (2)

Stack und Heap teilen sich gesamten zur
Verfügung stehenden Speicher
– Pro Prozess

Heap: dynamisch benötigter Speicher
 Stack: statisch verwendeter Speicher
6
Stack

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
7
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
8
Heap

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
9
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
10
Malloc

Fordere einen Speicherblock vom Heap an
ptr = 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
ptr
(0x01234567)
Speicherblock
Heap im Hauptspeicher
11
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 werden
int *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
12
Malloc (3)

Ähnliche Systemfunktionen:
– calloc

Andere 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();
13
Grundlagen von
Zeiger-Arithmetik

Ergebnis von “malloc” zeigt auf 1 Element des
spezifizierten Datentyps
ptr = (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)
14
Free

Angeforderte Speicherblöcke müssen wieder
freigegeben werden
free(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
15
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
16
Sizeof 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
17
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)
18
Sizeof Operator (3)

“sizeof” berechnet Größe eines Wertes oder eines
Datentyps
size = sizeof(int);
size = sizeof(struct myStruct);
size = sizeof myValue;
– Anzahl an Bytes, die die physisch Repräsentation im
Speicher benötigt
ptr = (int *)malloc(N * sizeof(int));

Kann bereits zur Übersetzungszeit errechnet
werden und belastet somit nicht die Laufzeit
19
Realloc

Vorgrößern von Speicherblöcken ist nicht direkt
möglich
– Andere Speicherblöcke können physisch im Speicher
direkt dahinter liegen
int *ptr = NULL;
int *biggerPtr = NULL;
ptr = (int *)malloc(orig_size);
…
biggerPtr = (int *)realloc(ptr, new_size);
20
Memset, memcpy, memmove

Angeforderte Speicherblöcke (malloc) sollten
immer initialisiert werden
memset(ptr, 0x00, size);
– Bei sicherheitskritischen Anwendung ist ein “Leeren”
vor dem Freigeben auch oft ratsam!

Kopieren zwischen überlappungsfreien
Speicherblöcken
memcpy(destination, source, size);

Kopieren zwischen überlappenden
Speicherblöcken
memmove(destination, source, size);
21
Richtlinien & Tipps

Speicherallokation 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
22
Richtlinien & Tipps (2)

Alle Variablen sofort bei der Deklaration
initialisieren
char *str = NULL;
int counter = 0;
str = (char *)malloc(strlen(orig_str)+1);
if (!str) { … }
memset(str, 0x00, strlen(orig_str)+1);
23
Potientielle 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
24
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
25
Herunterladen