- Speicherfragmentierung
-
Der dynamische Speicher, auch Heap (engl. für Halde, Haufen), Halden- oder Freispeicher ist ein Speicherbereich, aus dem zur Laufzeit eines Programms zusammenhängende Speicherabschnitte angefordert und in beliebiger Reihenfolge wieder freigegeben werden können. Die Freigabe kann sowohl manuell als auch mit Hilfe einer automatischen Speicherbereinigung erfolgen. Eine Speicheranforderung vom Heap bzw. Freispeicher wird auch dynamische Speicheranforderung genannt. Sie dient den Programmen dazu, über den vom Programmcode und den – fix reservierten – Datenfeldern und dem Stack (Stapelspeicher) belegten Speicher hinaus noch zusätzlichen Pufferspeicher zur Verfügung zu haben.
Inhaltsverzeichnis
Unterschied zum Stack
Der Unterschied zum Stack (Stapel- oder Kellerspeicher) besteht darin, dass beim Stack angeforderte Speicherabschnitte in der umgekehrten Reihenfolge wieder freigegeben werden müssen, in der sie angefordert wurden. Beim Stack spricht man auch von automatischer Speicheranforderung. Die Laufzeitkosten einer automatischen Speicheranforderung sind in der Regel deutlich geringer als die bei der dynamischen Speicheranforderung. Allerdings ist bei intensiver Nutzung durch sehr große oder sehr viele Anforderungen der für den Stack reservierte Speicher bald aufgebraucht - dann droht ein Programmabbruch wegen Stapelüberlaufs. Reserviert der Programmautor zu viel Stack, ist sein Programm ein „Speicherfresser“; reserviert er zu wenig, ist es eine „Performancebremse“. Im Unterschied dazu ist die dynamische Speicheranforderung nicht vom Programm selbst, sondern der vorhanden Laufumgebung abhängig.
Unterstützung von dynamischen Speicheranforderungen in Programmiersprachen
Programmiersprachen unterstützen die dynamische Speicheranforderung auf unterschiedliche Weisen. In ISO-C gibt es dafür beispielsweise die Funktionen malloc() und realloc(). Mit der Funktion free() wird der Speicher dann wieder freigegeben.
In ISO-C++ gibt es außer den bereits von C übernommenen Funktionen die Möglichkeit, Speicher dynamisch mit Hilfe von new anzufordern bzw. mit delete wieder freizugeben.
Speicherverwaltung
Im Gegensatz zum Stack ist die Verwaltung des Heaps durch die Laufzeitumgebung etwas komplizierter, da das Anfordern und Freigeben von Speicherabschnitten völlig dynamisch und unvorhersehbar erfolgen kann. An die dynamische Speicherverwaltung werden die folgenden, einander teilweise widersprechenden Anforderungen gestellt:
-
- Hohe Geschwindigkeit
- Effiziente Speichernutzung
- Geringer Verwaltungsaufwand
- Flexible und mächtige Bibliotheksroutinen (sofern solche überhaupt vorhanden sind)
Da Programme Speicherbereiche in unterschiedlichen Größen anfordern können, muss auch die Heap-Verwaltung Blöcke unterschiedlicher Größe bereit halten, da es Verschwendung wäre, z. B. einen Block mit 10 KiloByte zu reservieren, wenn das Programm gerade mal 100 Byte benötigt (best-fit Strategie).
Falls Blöcke auch geteilt werden können, kann es aber umgekehrt auch wieder sinnvoll sein, einen Block mit möglichst großem "Rest" zu reservieren (worst-fit Strategie). Die Überlegung ist, dass ein Bereich mit 900 Byte eher noch wo anders verwendet werden kann als ein Rest von 2 oder 3 Byte bei best-fit.
Ohne automatische Speicherbereinigung kann es durch Fragmentierung des zur Verfügung stehenden Gesamtspeicherbereiches so weit kommen, dass neue Speicheranforderungen nicht mehr erfüllt werden können, obwohl der insgesamt verfügbare freie Speicher noch ohne Weiteres ausreichen würde. Der Grund ist, dass auch der virtuelle Adressraum, auf den sämtliche Adressen abgebildet werden müssen, nicht unbegrenzt ist. Bei einem 32-Bit-Betriebssystem (d.h. bei einem System mit 32-Bit breitem Adressbus) hat der virtuelle Adressraum je Prozess eine Maximalgröße von 232 Adressen (das entspricht 4 GiB (Gibibyte)), von denen das Betriebssystem selbst gewöhnlich einen erheblichen Anteil für sich beansprucht.
Für die Anwendungsentwicklung bedeutet die dynamische Speicherverwaltung einen erheblichen zusätzlichen Aufwand und bildet eine häufige Fehlerquelle, insbesondere für Speicherlecks. Ein typischer Fehler ist zum Beispiel, dass Referenzen auf dynamisch belegten Speicher unbeabsichtigt überschrieben werden und der ursprünglich referenzierte Bereich nicht mehr freigegeben werden kann. Dies kann dann auch zu sogenannten hängenden Zeigern führen.
Die dynamische Speicherverwaltung bietet dem Anwendungsentwickler die Möglichkeit, die Verwendung des Speichers innerhalb der Anwendung selbst zu steuern. Dies ist insbesondere bei systemnahen Anwendungen, Echtzeitanwendungen oder mobilen Anwendungen von Bedeutung, da hier die nicht-funktionalen Anforderungen gegenüber dem Speicherbedarf beziehungsweise dem Antwortzeitverhalten normaler Anwendungen abweichen können. Durch die stetig wachsende Leistungsfähigkeit der Hardware tritt dieser Aspekt jedoch immer weiter in den Hintergrund.
Weblinks
- Herbert Glarner's Speicherverwaltung: Sourcecode, Beschreibung effizienter Mechanismen, Visualisierung [en]
- Heap-Fragmentierung: Problem und Lösungsansätze
Weiterführende Artikel
- Speicherüberlauf bei der dynamischen Speicheranforderung. Siehe Heap Overflow.
-
Wikimedia Foundation.