1 - Adressraumstruktur [ID:18272]
50 von 127 angezeigt

Wir kommen zur nächsten Übung in der Systemprogrammierung. Diesmal wollen wir uns anschauen, wie der Adressraum

eines Prozesses aussieht. Dazu haben wir folgendes kleines Codebeispiel. Im Folgenden wollen

wir uns den Adressraum aufzeichnen, der entsteht, wenn wir dieses Beispiel kompilieren und ausführen.

Das Beispiel besteht aus einigen globalen Variablen, nämlich den Static Integern a-c

und einem konstanten Integer f. Außerdem haben wir ein String helloWorld, auf dem der Zeiger

s zeigt. Darüber hinaus gibt es eine Funktion main, die wiederum zwei lokale Variablen hat.

Einmal die Integer Variable g und eine Static Integer Variable h. Ein Adressraum sieht ungefähr

aus wie hier abgebildet. Wir haben an den hohen Adressen das Stack-Segment, in dem die

lokalen Variablen liegen. An den niedrigen Adressen haben wir das Code-Segment, auch

genannt Text-Segment, in dem die ausführbaren Instruktionen des Programms liegen. Außerdem

liegen hier auch die Konstanten, wie zum Beispiel der Wert 42, der Variable f, oder eben der

String helloWorld. An den Adressen darüber haben wir einmal das Punkt Data-Segment und

dann das Punkt BSS-Segment. Im Punkt Data und Punkt BSS liegen ebenfalls globale Variablen.

Diese sind jedoch les- und schreibbar. Der Unterschied zwischen Punkt Data und Punkt

BSS ist, dass im Punkt BSS alle nicht initialisierten Daten liegen. Das bedeutet alle Variablen,

denen im Quellcode kein Wert zugewiesen wurde. Diese werden automatisch mit dem Wert Null

initialisiert beim Laden des Programms. In dem Beispiel betrifft das zum einen die Variable

b, der kein Wert zugewiesen wird. Abhängig vom Compiler kann es auch sein, dass Variablen,

die explizit mit dem Wert Null initialisiert werden, ebenfalls in das Punkt BSS-Segment

verortet werden. Alle initialisierten Daten, wie zum Beispiel die Variable a und der Zeiger

s, liegen im Punkt Data-Segment. Hier nochmal eine kurze Erinnerung, was das Schlüsselwort

Static bedeutet. Im Kontext von globalen Variablen bedeutet Static, dass der Name der Variable

nur innerhalb des Moduls sichtbar ist. Das bedeutet andere C-Module können über den

Namen nicht auf die Variable zugreifen. Wenn Static jedoch an lokale Variablen innerhalb

von Funktionen geschrieben wird, hat es eine etwas andere Bedeutung. In dem Fall bedeutet

es, dass der Wert der Variable über Funktionsaufrufe hinweg erhalten bleibt. Damit dies umgesetzt

werden kann, darf die Variable nicht auf dem Stack stehen, da dieser nach dem Ausführen

des Return Statements aufgeräumt wird und die Werte, die der jeweiligen Funktion auf

dem Stack zugeordnet waren, verloren sind. Als Konsequenz müssen statisch lokale Variablen

also ebenfalls im Daten-Segment liegen. An dieser Stelle fragt man sich vielleicht, warum

man die Unterscheidung zwischen einem Data- und einem BSS-Segment trifft, wo es doch möglich

wäre, die Daten aus dem BSS-Segment einfach explizit mit Null zu initialisieren und ebenfalls

ins Data-Segment zu schreiben. Der Grund dafür liegt in der praktischen Umsetzung. Alle initialisierten

Variablen müssen im ausführbaren Programm gespeichert werden, damit zum Zeitpunkt des

Ladens des Programms die Werte in den Speicher geschrieben werden können. Das bedeutet,

für jede Variable brauche ich einen extra Speicherplatz, der ebenfalls in der Binärdatei

auf der Festplatte allokiert sein muss. Wenn ich nun jedoch eine große Menge von nicht

initialisierten Daten habe, die implizit mit dem Wert Null vorbelegt werden, reicht das,

wenn ich mir merke, wie viel Byte ich mit Null initialisieren möchte und brauche nicht

für jede Variable selbst den Wert Null in der ausführbaren Datei zu speichern.

Damit sinkt der Speicherverbrauch auf der Festplatte. Das könnt ihr auch beobachten,

wenn ihr euch nun noch einmal eure Halde anschaut. In der Halde allokiert ihr über einen Megabyte

statisch in einem Array. Das ausführbare Programm jedoch verbraucht auf der Festplatte

weniger als einen Megabyte Speicher, eben weil in dem Binary der Verweis steht, dass

zum Zeitpunkt des Ladens des Programms 1 Megabyte Nullen in den Speicher geschrieben

werden sollen, anstelle dass tatsächlich 1 Megabyte Nullen in dem Binary stehen.

Was nun auffällt ist, dass zwischen dem Stack-Segment und dem Heap, der aus dem Punkt Daten und

Punkt BSS-Segment besteht, ein großer freier Platz ist. Dies ist bewusst, damit zur Laufzeit

neue Speicher allokiert werden kann. So wächst der Stack zum Beispiel von hohen Adressen

nach unten zu niedrigen, während der Heap von niedrigen Adressen nach hohen wächst.

Teil einer Videoserie :
Teil eines Kapitels:
Prozesse

Zugänglich über

Offener Zugang

Dauer

00:11:46 Min

Aufnahmedatum

2020-06-21

Hochgeladen am

2020-06-21 23:26:34

Sprache

de-DE

Einbetten
Wordpress FAU Plugin
iFrame
Teilen