Zum Inhalt springen

„Garbage Collection“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
Leistungsfähigkeit: NPOV (auch zweiteres ist ein Microbenchmark)
Leistungsfähigkeit: Manuelle Speicherfreigabe erhöht wiederum Gefahr von Memoryleaks
Zeile 47: Zeile 47:


=== Leistungsfähigkeit ===
=== Leistungsfähigkeit ===
Ob eine automatische Speicherbereinigung Programme insgesamt beschleunigt oder ausbremst ist umstritten. In einigen Kontexten, wie z.B. wenn Speicher erst dann freigegeben wird, wenn die Systemanforderungen gerade niedrig sind oder wenn die Speicherverwaltung des Systems durch Defragmentierung entlastet wird, kann sie zu Leistungssteigerungen führen.<ref>Benjamin Zorn, The Measured Cost of Conservative Garbage Collection Software - Practice and Experience 23(7): 733-756, 1992</ref> Es existieren [[EDV-Benchmark|Microbenchmarks]], welche belegen, dass bei Programmiersprachen mit automatischer Speicherbereinigung die Anlage/Freigabe von Objekten in Summe schneller vonstattengeht als ohne,<ref>{{cite web | url=http://www.ddj.com/java/184401976?pgno=9 | title=Microbenchmarking C++, C#, and Java: Object creation/ destruction and method call | publisher=[[Dr. Dobb's Journal]] | date=2005-07-01 | accessdate=2009-10-26}}</ref><ref>{{cite web | author=Arne Schäpers, Rudolf Huttary | date=Dezember 2003 | title=Daniel Düsentrieb - C#, Java, C++ und Delphi im Effizienztest, Teil 2 | publisher=[[c’t]] | pages=222-227 | url=http://www.heise.de/kiosk/archiv/ct/2003/21/222_C-,-Java,-C-und-Delphi-im-Effizienztest,-Teil-2 | accessdate=2009-10-26 | quote="Die Ergebnisse zeigen erstens, dass ein Garbage Collector (bei der Destruktion) vom Laufzeitverhalten her keine spürbaren Nachteile zu bringen scheint" und "Der teilweise schon fast doppelte Zeitbedarf von C++ bei der Konstruktion gegenüber den anderen Kandidaten..."}}</ref> jedoch auch Microbenchmarks die insgesamt einen überwiegend negativen Einfluß auf die Leistungsfähigkeit sehen.<ref name="hundt2011">{{cite web| last=Hundt | first=Robert |language=englisch |title=Loop Recognition in C++/Java/Go/Scala | publisher=[[Scala Days]] 2011 | date=2011-04-27|location=Stanford, California | accessdate=2012-11-17 | url=https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf|quote=''We find that in regards to performance, C++ wins out by a large margin. [...] The Java version was probably the simplest to implement, but the hardest to analyze for performance. Specifically the effects around garbage collection were complicated and very hard to tune''}}</ref>
Ob eine automatische Speicherbereinigung Programme insgesamt beschleunigt oder ausbremst ist umstritten. In einigen Kontexten, wie z.B. wenn Speicher erst dann freigegeben wird, wenn die Systemanforderungen gerade niedrig sind oder wenn die Speicherverwaltung des Systems durch Defragmentierung entlastet wird, kann sie zu Leistungssteigerungen führen.<ref>Benjamin Zorn, The Measured Cost of Conservative Garbage Collection Software - Practice and Experience 23(7): 733-756, 1992</ref> Darüberhinaus ist eine Speicheranforderung und -freigabe via Betriebssystem oft deutlich langsamer als wenn der Speicher durch die Ablaufumgebung gemanaged wird. Es existieren [[EDV-Benchmark|Microbenchmarks]], welche belegen, dass bei Programmiersprachen mit automatischer Speicherbereinigung die Anlage/Freigabe von Objekten in Summe schneller vonstattengeht als ohne,<ref>{{cite web | url=http://www.ddj.com/java/184401976?pgno=9 | title=Microbenchmarking C++, C#, and Java: Object creation/ destruction and method call | publisher=[[Dr. Dobb's Journal]] | date=2005-07-01 | accessdate=2009-10-26}}</ref><ref>{{cite web | author=Arne Schäpers, Rudolf Huttary | date=Dezember 2003 | title=Daniel Düsentrieb - C#, Java, C++ und Delphi im Effizienztest, Teil 2 | publisher=[[c’t]] | pages=222-227 | url=http://www.heise.de/kiosk/archiv/ct/2003/21/222_C-,-Java,-C-und-Delphi-im-Effizienztest,-Teil-2 | accessdate=2009-10-26 | quote="Die Ergebnisse zeigen erstens, dass ein Garbage Collector (bei der Destruktion) vom Laufzeitverhalten her keine spürbaren Nachteile zu bringen scheint" und "Der teilweise schon fast doppelte Zeitbedarf von C++ bei der Konstruktion gegenüber den anderen Kandidaten..."}}</ref> jedoch auch Microbenchmarks die insgesamt einen überwiegend negativen Einfluß auf die Leistungsfähigkeit sehen.<ref name="hundt2011">{{cite web| last=Hundt | first=Robert |language=englisch |title=Loop Recognition in C++/Java/Go/Scala | publisher=[[Scala Days]] 2011 | date=2011-04-27|location=Stanford, California | accessdate=2012-11-17 | url=https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf|quote=''We find that in regards to performance, C++ wins out by a large margin. [...] The Java version was probably the simplest to implement, but the hardest to analyze for performance. Specifically the effects around garbage collection were complicated and very hard to tune''}}</ref>


Beim Speicherverbrauch führt eine automatische Speicherverwaltung und -bereinigung immer zu einem gewissen [[Overhead (EDV)|Overhead]] gegenüber einem expliziten, händischen Speichermanagment aufgrund der zeitverzögerten Bereinigung.<ref name="hundt2011"/><ref>{{cite web|url=http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.14.1816&rep=rep1&type=pdf|quote=''Conservative garbage collection does not come without a cost. In the programs measured, the garbage collection algorithm used 30–150 per cent more address space than the most space efficient explicit management algorithm. In addition, the conservative garbage collection algorithm significantly reduced the reference locality of the programs, greatly increasing the page fault rate and cache miss rate of the applications for a large range of cache and memory sizes. This result suggests that not only does the conservative garbage collection algorithm increase the size of the address space, but also frequently references the entire space it requires.''|first=Benjamin|last=Zorn|title=The Measured Cost of Conservative Garbage Collection|publisher=Department of Computer Science, [[University of Colorado Boulder]]|language=englisch|accessdate=2012-11-18|date=1993-01-22}}</ref>
Beim Speicherverbrauch führt eine automatische Speicherverwaltung und -bereinigung zu einem gewissen [[Overhead (EDV)|Overhead]] gegenüber einem korrekt implementierten händischen Speichermanagment aufgrund der zeitverzögerten Bereinigung.<ref name="hundt2011"/><ref>{{cite web|url=http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.14.1816&rep=rep1&type=pdf|quote=''Conservative garbage collection does not come without a cost. In the programs measured, the garbage collection algorithm used 30–150 per cent more address space than the most space efficient explicit management algorithm. In addition, the conservative garbage collection algorithm significantly reduced the reference locality of the programs, greatly increasing the page fault rate and cache miss rate of the applications for a large range of cache and memory sizes. This result suggests that not only does the conservative garbage collection algorithm increase the size of the address space, but also frequently references the entire space it requires.''|first=Benjamin|last=Zorn|title=The Measured Cost of Conservative Garbage Collection|publisher=Department of Computer Science, [[University of Colorado Boulder]]|language=englisch|accessdate=2012-11-18|date=1993-01-22}}</ref> Andererseits ist eine korrekte Implemetierung manueller Speicherfreigabe in nicht trivialen Programmen komplex umzusetzen, was Fehlerquellen für [[Speicherleck#Explizite_Speicherfreigabe|Speicherlecks bei manueller Speicherfreigabe]] schafft. Beispielsweise kann die oft angewandte Methode der [[Referenzzählung]] keine zyklischen Referenzen erkennen und führt ohne Ergänzung durch komplexe Algorithmen zu Speicherlecks.


== Verbreitung ==
== Verbreitung ==

Version vom 18. November 2012, 23:19 Uhr

Die Garbage Collection (kurz GC, vom englischen garbage collection, wörtlich: „Müllabfuhr“, auch Automatische Speicherbereinigung oder Freispeichersammlung genannt) bezeichnet in der Softwaretechnik im idealen Fall die Minimierung des Speicheranspruches eines Prozesses, die sowohl während der Software-Entwicklung als auch während der Laufzeit ohne Aufwand stattfindet. Dabei bieten sich in der Praxis die Freigabe oder Wiederverwendung nicht länger benötigter Speicherbereiche an, die aber schon dem Prozess zugeteilt wurden. Auch die Beseitigung externer Fragmentierung bietet sich an. Bezüglich der Zeit- und Speicher-Komplexität gibt es mehr oder weniger deutliche Abweichungen vom Ideal.

In vielen Softwaresystemen wird Speicherplatz bei Bedarf reserviert, um die Angaben zu einem Datenobjekt zu speichern. Wird nach Abarbeitung eines Programmteils das Objekt nicht mehr verwendet, so sollte der Platz für das Objekt auch wieder verfügbar gemacht werden. Diese Aufgabe erledigt eine Garbage-Collector genannte Routine automatisch, ohne dass dies explizit im Programm kodiert sein müsste. Darüber hinaus kann die automatische Speicherbereinigung in der Regel auch zu jedem Zeitpunkt in einem laufenden Programm aufgerufen werden.

Algorithmen

Es gibt verschiedene Speicherbereinigungsalgorithmen, einige davon bekämpfen auch das Problem der Speicherfragmentierung. Es gibt zwei grundsätzlich verschiedene Funktionsweisen: Verfolgung (tracing garbage collectors) und Referenzzählung.

Verfolgende Algorithmen

Mark-and-Sweep-Algorithmus

Bei diesem Verfahren der Speicherbereinigung wird von bekanntermaßen noch benutzten Objekten ausgehend allen Verweisen auf andere Objekte gefolgt. Jedes so erreichte Objekt wird markiert. Anschließend werden alle nicht markierten Objekte zur Wiederverwendung freigegeben.

Die Freigabe kann zur Speicherfragmentierung führen. Das Problem ist hierbei jedoch etwas geringer als bei manueller Speicherverwaltung. Während bei manueller Speicherverwaltung die Deallozierung immer sofort erfolgt, werden bei Mark-and-Sweep fast immer mehrere Objekte auf einmal beseitigt, wodurch größere zusammenhängende Speicherbereiche frei werden können.

Mark-and-Compact-Algorithmus

Der Mark-and-Compact-Algorithmus benutzt ebenso wie Mark-and-Sweep das Prinzip der Erreichbarkeit in Graphen, um noch referenzierte Objekte zu erkennen. Diese kopiert er an eine andere Stelle im Speicher. Der ganze Bereich, aus dem die noch referenzierten (man spricht hier auch von „lebenden“) Objekte herauskopiert wurden, wird nun als freier Speicherbereich betrachtet.

Nachteil dieser Methode ist das Verschieben der „lebenden“ Objekte selber, denn Zeiger auf diese werden ungültig und müssen angepasst werden. Hierzu gibt es grundsätzlich wenigstens zwei Verfahren:

  1. Jedes Objekt wird über zwei Indirektionen (Umleitungen) angesprochen (über einen Zeiger auf einen Zeiger auf das Objekt), so dass beim Verschieben nur noch der Zeiger, der direkt auf das Objekt zeigt, angepasst werden muss.
  2. Alle Referenzen verweisen direkt auf das Objekt, um aufwändige Dereferenzierungen zu vermeiden, und werden nach einer Verschiebung geeignet angepasst.

Das Verschieben der Objekte hat allerdings den Vorteil, dass jene, die die Bereinigung „überlebt“ haben, nun alle kompaktiert zusammenliegen und der Speicher damit praktisch defragmentiert ist. Auch ist es möglich, sehr schnell zu allozieren, weil freier Speicherplatz nicht aufwändig gesucht wird. Anschaulich: Werden die referenzierten Objekte an den „Anfang“ des Speichers verschoben, kann neuer Speicher einfach am „Ende“, hinter dem letzten lebenden Objekt, alloziert werden. Das Allozieren funktioniert damit vergleichsweise einfach, ähnlich wie beim Stack.

Generationell

Generationelle GCs verkürzen die Laufzeit der Speicherfreigabe. Dazu wird die Situation ausgenutzt, dass in der Praxis die Lebensdauer von Objekten meist sehr unterschiedlich ist: Auf der einen Seite existieren Objekte, die die gesamte Laufzeit der Applikation überleben. Auf der anderen Seite gibt es eine große Menge von Objekten, die nur temporär für die Durchführung einer einzelnen Aufgabe benötigt werden. Der Speicher wird bei generationellen GCs in mehrere Teilbereiche (Generationen) aufgeteilt. Die Langlebigkeit wird durch einen Zähler quantifiziert, welcher bei jeder Garbage-Collection inkrementiert wird. Mit jeder Anwendung des Freigabe-Algorithmus (zum Beispiel Mark-and-Compact oder Stop-And-Copy) werden langlebige Objekte in eine höhere Generation verschoben. Der Vorteil liegt darin, dass die Speicherbereinigung für niedrige Generationen häufiger und schneller durchgeführt werden kann, da nur ein Teil der Objekte verschoben und deren Zeiger verändert werden müssen. Höhere Generationen enthalten mit hoher Wahrscheinlichkeit nur lebende (bzw. sehr wenige tote) Objekte und müssen deshalb seltener bereinigt werden.

Die Anzahl der Generationen wird heuristisch festgelegt (zum Beispiel 3 in .NET, 2 in der Java-VM von Sun). Zudem können für jede Generation unterschiedliche Algorithmen verwendet werden. In Java beispielsweise wird für die niedrigste Generation (auch Young-Generation genannt) ein modifizierter Stop-And-Copy-Algorithmus angewandt, für die höhere (Tenured-Generation) Mark-And-Compact.

Referenzzählung

Bei diesem Verfahren führt jedes Objekt einen Zähler mit der Anzahl aller Referenzen, die auf dieses Objekt zeigen. Fällt der Referenzzähler eines Objektes auf null, so kann es freigegeben werden.

Ein besonderes Problem der Freispeichersammlung mit Referenzzählung liegt in so genannten zyklischen Referenzen, bei denen Objekte Referenzen aufeinander halten, aber sonst von keinem Konsumenten im System mehr verwendet werden. Nehmen wir beispielsweise an, Objekt A halte eine Referenz auf Objekt B und umgekehrt, während der Rest des Systems ihre Dienste nicht mehr benötigt. Somit verweisen beide Objekte gegenseitig (zyklisch) aufeinander, weshalb die automatische Speicherbereinigung nicht ohne weiteres erkennen kann, dass sie nicht mehr benutzt werden. Die Folge hiervon ist, dass der Speicher somit für die Dauer der Programmausführung belegt bleibt. Es gibt unterschiedliche Algorithmen, die solche Situationen erkennen und auflösen können, zumeist nach dem Prinzip der Erreichbarkeit in Graphen.

Konsequenzen

Einige Programmierfehler, die den Umgang mit Ressourcen betreffen, können durch Garbage Collection ganz vermieden werden. Besonders zu erwähnen sind hierbei die doppelte Freigabe von Ressourcen und die Dereferenzierung von versehentlich zu früh freigegebenen Ressourcen (Hängende Zeiger).

Die Analyse und Freigabe von zehn Millionen Zeigern dauert auf modernen Rechenmaschinen mit effizienten Laufzeitsystemen nur Bruchteile einer Sekunde. Ein Nachteil, den einige Algorithmen der automatischen Speicherbereinigung mit sich bringen können, ist, dass der Zeitpunkt ihrer Durchführung unter Umständen nicht vorherzusehen ist. So ist es in Echtzeitsystemen nicht hinnehmbar, wenn die Programmausführung zu nicht voraussehbaren Zeitpunkten durch die Ausführung der automatischen Speicherbereinigung unterbrochen wird. Für Echtzeitsysteme muss eine automatische Speicherbereinigung präemptiv (zum Beispiel im Leerlaufprozess) und inkrementell implementiert werden. Einfache inkrementelle Verfahren arbeiten zum Beispiel mit der sogenannten Dreifarb-Markierung.[1]

Als Folge des Satzes von Rice kann nicht festgestellt werden, ob noch referenzierte Objekte jemals wieder benutzt werden. Darum gibt eine automatische Speicherbereinigung nur vom Programm nicht mehr referenzierte Objekte frei und kann somit Speicherlecks nicht verhindern.

Leistungsfähigkeit

Ob eine automatische Speicherbereinigung Programme insgesamt beschleunigt oder ausbremst ist umstritten. In einigen Kontexten, wie z.B. wenn Speicher erst dann freigegeben wird, wenn die Systemanforderungen gerade niedrig sind oder wenn die Speicherverwaltung des Systems durch Defragmentierung entlastet wird, kann sie zu Leistungssteigerungen führen.[2] Darüberhinaus ist eine Speicheranforderung und -freigabe via Betriebssystem oft deutlich langsamer als wenn der Speicher durch die Ablaufumgebung gemanaged wird. Es existieren Microbenchmarks, welche belegen, dass bei Programmiersprachen mit automatischer Speicherbereinigung die Anlage/Freigabe von Objekten in Summe schneller vonstattengeht als ohne,[3][4] jedoch auch Microbenchmarks die insgesamt einen überwiegend negativen Einfluß auf die Leistungsfähigkeit sehen.[5]

Beim Speicherverbrauch führt eine automatische Speicherverwaltung und -bereinigung zu einem gewissen Overhead gegenüber einem korrekt implementierten händischen Speichermanagment aufgrund der zeitverzögerten Bereinigung.[5][6] Andererseits ist eine korrekte Implemetierung manueller Speicherfreigabe in nicht trivialen Programmen komplex umzusetzen, was Fehlerquellen für Speicherlecks bei manueller Speicherfreigabe schafft. Beispielsweise kann die oft angewandte Methode der Referenzzählung keine zyklischen Referenzen erkennen und führt ohne Ergänzung durch komplexe Algorithmen zu Speicherlecks.

Verbreitung

Einige ältere (APL, LISP, BASIC) und viele moderne Programmiersprachen verfügen über eine integrierte automatische Speicherbereinigung.

Für Programmiersprachen wie C, bei denen die Programmierer die Speicherverwaltung „von Hand“ erledigen müssen, gibt es teilweise Bibliotheken, die eine automatische Speicherbereinigung zur Verfügung stellen, was bei der Programmierung aber leicht umgangen werden kann, beziehungsweise bei systemnaher Programmierung sogar umgangen werden muss. Aus diesem Grund werden in modernen Entwicklungsumgebungen systemnah programmierte Module von der automatischen Speicherbereinigung ausgenommen, indem sie explizit gekennzeichnet werden (zum Beispiel in C# mit der Option /unsafe oder in Component Pascal mit der obligatorischen Anweisung IMPORT SYSTEM).

Weitere Beispiele für Programmiersprachen mit einer automatischen Speicherverwaltung sind Smalltalk, Haskell, Java, Oberon, Python, OCaml, Perl, Visual Objects, ABAP und Objective-C (ab Version 2.0) sowie alle Sprachen, die für die Common Language Runtime von .NET entwickelt wurden (zum Beispiel C# oder VB.NET).

Konservative und nicht-konservative Speicherbereinigung

Unter einer konservativen automatischen Speicherbereinigung versteht man eine, die nicht zuverlässig alle nicht-referenzierten Objekte erkennen kann. Diese hat meistens keine Informationen darüber, wo sich im Speicher Referenzen auf andere Objekte befinden.

Während einem nicht-konservativen Kollektor (manchmal auch als „exakter Kollektor“ bezeichnet) Metadaten vorliegen, anhand derer er alle Referenzen innerhalb von Objekten und Stackframes auffinden kann, muss ein konservativer den Speicher auf mögliche Referenzen durchsuchen. Jede Bitfolge, die eine gültige Referenz in den Speicher sein könnte, wird als Referenz angenommen. Es kann dabei nicht festgestellt werden, ob es sich dabei nicht doch um ein Zufallsmuster handelt. Daher erkennen konservative Kollektoren gelegentlich Objekte als referenziert, obwohl sie es eigentlich nicht sind. Da eine automatische Speicherbereinigung niemals Objekte entfernen darf, die noch gebraucht werden könnten, muss sie konservativ annehmen, dass es sich bei der erkannten Bitfolge um eine Referenz handelt.

Insbesondere wenn eine automatische Speicherbereinigung auch dringlichere Ressourcen als Speicher freigeben muss (siehe Finalisierung), kann ein konservativer Kollektor ein Risiko darstellen. Im Allgemeinen findet man konservative GCs dort, wo eine Implementierung der automatischen Speicherverwaltung schwierig ist, zum Beispiel für die Sprachen C++ und C. (Anmerkung: Dies gilt nicht für die „verwalteten Typen“ in C++/CLI, da dort eigene Referenztypen für die automatische Speicherbereinigung eingeführt wurden, die es nicht erlauben, direkt die Adresse eines Objekts auszulesen.)

Finalisierung

Die in einigen Systemen verbreitete Technik, Objekte im Zuge der automatischen Speicherbereinigung zu deinitialisieren - also vor der Speicherfreigabe noch bestimmte Aufgaben durchzuführen, bezeichnet man auch als Finalisierung. Beispielsweise verfügen Objekte in der Programmiersprache Java über eine spezielle Methode namens finalize, die für ebendiese Zwecke überschrieben werden kann.

Dieses Verfahren, also Objekt-Deinitialisierungen im Zuge der automatischen Speicherbereinigung durchzuführen, kann, insbesondere wenn es dabei um die Freigabe von Ressourcen geht, in der Praxis zu Problemen führen. Folgende Probleme können sich durch Finalisierung ergeben:

  • Objekte, die Ressourcen verwalten, sollten diese nicht erst im Zuge der Finalisierung freigeben. Ansonsten könnte das zu blockierenden Zuständen innerhalb des Programmablaufs führen, da der Zeitpunkt der Finalisierung nicht vorhersagbar ist.
  • Finalisierung erzeugt zusätzliche Rechenlast für die automatische Speicherbereinigung welche möglichst rasch und ohne den Rest des Programmablaufes zu stören durchgeführt werden sollte.
  • Es gibt keine definierte Finalisierungsreihenfolge. Daher kann es geschehen, dass während der Finalisierung auf andere Objekte zugegriffen wird, die ebenfalls der Finalisierung unterworfen sind, zu diesem Zeitpunkt aber überhaupt nicht mehr existieren.
  • Es gibt je nach Implementierung (beispielsweise in der Programmiersprache Java) keine Garantie dafür, dass die Finalisierungsroutine von der automatischen Speicherbereinigung überhaupt aufgerufen wird.

Aus diesen Gründen sollte man versuchen, komplett auf Finalisierung zu verzichten. Der automatischen Speicherbereinigung fällt dann also ausschließlich die Aufgabe der Speicherverwaltung zu.

Fragmentierung

Traditionelle Speicherverwaltungen neigen im Laufe der Zeit zur Fragmentierung. Verursacht wird dieses Problem durch die unterschiedliche Lebenszeit von Objekten. Die Speicherverwaltung führt Buch darüber, welche Stellen „freien Speicher“ repräsentieren, also alloziert werden können und welche bereits von Objekten belegt sind. Durch das explizite Freigeben von Speicherstellen entstehen Lücken, die nicht immer sofort wieder aufgefüllt werden können. Wenn neue Objekte größer sind als die freigewordenen Lücken, muss an anderer Stelle ein nicht allozierter Bereich gesucht werden.

Probleme, die bei Fragmentierung auftreten können:

  • Es bleibt ein gewisser Teil des zur Verfügung stehenden Speichers ungenutzt.
  • Das Allozieren von Speicher dauert länger, wenn die Datenstrukturen, über die der Heap verwaltet wird, komplexer werden. Das Suchen nach einer freien Speicherstelle von passender Größe gestaltet sich aufwändiger.
  • Es kommt immer wieder vor, dass nacheinander allozierte Objekte nicht nebeneinander im Speicher stehen (man spricht hierbei von schlechter Speicherlokalität). Untersuchungen haben gezeigt, dass nacheinander erzeugte Objekte oft gleichzeitig für eine bestimmte Operation gebraucht werden. Wenn sie nicht nahe genug beieinander liegen, werden Zugriffe anstatt auf den schnellen Cache-Speicher auf den dahinterliegenden, langsameren Speicher umgeleitet, was den Zugriff stark bremsen kann.

Durch kompaktierende Algorithmen kann eine Fragmentierung jedoch komplett vermieden werden. Siehe dazu Mark and Compact. Dies führt zwar zu einer längeren Verzögerung beim Freigeben von Speicher, reduziert allerdings die Allozierungsdauer. Um die Speicherfreigabe möglichst kurz zu halten, wird darauf geachtet, möglichst selten große Speicherbereiche aufzuräumen. Deshalb werden diese Algorithmen bevorzugt in Kombination mit generationellen Verfahren eingesetzt.

Siehe auch

Literatur

  • Richard Jones, Rafael Lins: Garbage Collection. John Wiley and Sons Ltd, 30. April 1996, ISBN 0-471-94148-4

Einzelnachweise

  1. Garbage Collection für Parallele und Verteilte Systeme, Frank Joachim Frey, 7. Mai 2002
  2. Benjamin Zorn, The Measured Cost of Conservative Garbage Collection Software - Practice and Experience 23(7): 733-756, 1992
  3. Microbenchmarking C++, C#, and Java: Object creation/ destruction and method call. Dr. Dobb's Journal, 1. Juli 2005, abgerufen am 26. Oktober 2009.
  4. Arne Schäpers, Rudolf Huttary: Daniel Düsentrieb - C#, Java, C++ und Delphi im Effizienztest, Teil 2. c’t, Dezember 2003, S. 222-227, abgerufen am 26. Oktober 2009: „"Die Ergebnisse zeigen erstens, dass ein Garbage Collector (bei der Destruktion) vom Laufzeitverhalten her keine spürbaren Nachteile zu bringen scheint" und "Der teilweise schon fast doppelte Zeitbedarf von C++ bei der Konstruktion gegenüber den anderen Kandidaten..."“
  5. a b Robert Hundt: Loop Recognition in C++/Java/Go/Scala. Scala Days 2011, 27. April 2011, abgerufen am 17. November 2012 (englisch): „We find that in regards to performance, C++ wins out by a large margin. [...] The Java version was probably the simplest to implement, but the hardest to analyze for performance. Specifically the effects around garbage collection were complicated and very hard to tune
  6. Benjamin Zorn: The Measured Cost of Conservative Garbage Collection. Department of Computer Science, University of Colorado Boulder, 22. Januar 1993, abgerufen am 18. November 2012 (englisch): „Conservative garbage collection does not come without a cost. In the programs measured, the garbage collection algorithm used 30–150 per cent more address space than the most space efficient explicit management algorithm. In addition, the conservative garbage collection algorithm significantly reduced the reference locality of the programs, greatly increasing the page fault rate and cache miss rate of the applications for a large range of cache and memory sizes. This result suggests that not only does the conservative garbage collection algorithm increase the size of the address space, but also frequently references the entire space it requires.