Warum zerstört die JVM eine Ressource nicht, sobald ihre Referenzzahl 0 erreicht?

8

Ich habe mich immer gefragt, warum der Garbage Collector in Java aktiviert wird, wann immer es sich anfühlt, anstatt zu tun:

%Vor%

Gibt es irgendwelche großen Vorteile gegenüber Java, die ich übersehen habe?

Danke

    
jmasterx 08.01.2012, 21:21
quelle

5 Antworten

17

Jede JVM ist anders, aber die HotSpot-JVM verlässt sich nicht primär auf die Referenzzählung als Mittel zur Speicherbereinigung. Das Referenzzählen hat den Vorteil, dass es einfach zu implementieren ist, aber es ist inhärent fehleranfällig. Insbesondere wenn Sie einen Referenzzyklus haben (eine Menge von Objekten, die sich alle in einem Zyklus aufeinander beziehen), wird die Referenzzählung diese Objekte nicht korrekt zurückgewinnen, da sie alle eine Referenzzahl ungleich Null haben. Dies zwingt Sie, von Zeit zu Zeit einen zusätzlichen Garbage-Collector zu verwenden, der dazu neigt, langsamer zu sein (Mozilla Firefox hatte genau dieses Problem, und seine Lösung bestand darin, einen Garbage-Collector auf Kosten der Codelesbarkeit hinzuzufügen). Aus diesem Grund haben Sprachen wie C ++ zum Beispiel eine Kombination aus shared_ptr s, die Referenzzählung verwendet, und weak_ptr s, die keine Referenzzyklen verwenden.

Darüber hinaus macht das Zuordnen einer Referenzzählung zu jedem Objekt die Kosten für das Zuweisen einer Referenz größer als normal, da die zusätzliche Buchhaltung die Anpassung der Referenzzählung (die sich nur bei Vorhandensein von Multithreading verschlechtert) zur Folge hat. Darüber hinaus schließt die Verwendung von Referenzzählung die Verwendung bestimmter Typen von Speicherzuordnern aus, was ein Problem darstellen kann. Es neigt auch dazu, in seiner naiven Form zur Heap-Fragmentierung zu führen, da Objekte durch den Speicher verstreut anstatt dicht gepackt werden, wodurch die Zuordnungszeiten verringert werden und eine schlechte Lokalisierung verursacht wird.

Die HotSpot-JVM verwendet eine Vielzahl von verschiedenen Techniken, um die Garbage Collection durchzuführen. Der primäre Garbage Collector wird jedoch als Stop-and-Copy-Collector bezeichnet. Dieser Kollektor arbeitet, indem er Objekte zusammenhängend im Speicher nebeneinander zuordnet und extrem schnelle (ein oder zwei Assemblierungsbefehle) die Zuweisung neuer Objekte ermöglicht. Wenn kein Platz mehr vorhanden ist, werden alle neuen Objekte gleichzeitig erfasst, was normalerweise die meisten der neu erstellten Objekte zum Absturz bringt. Als Ergebnis ist der GC viel schneller als eine typische referenzzählende Implementierung und hat letztendlich eine bessere Lokalität und bessere Leistung.

Für einen Vergleich der Techniken der Müllsammlung, zusammen mit einem schnellen Überblick darüber, wie der GC in HotSpot funktioniert, sollten Sie sich diese Vorlesungsfolien aus einem Compiler-Kurs, den ich letzten Sommer unterrichtet habe. Sie können sich auch das HotSpot-Whitepaper zur Garbage Collection ansehen Das geht viel ausführlicher darüber, wie der Garbage Collector funktioniert, einschließlich Möglichkeiten, den Collector für jede Anwendung individuell anzupassen.

Hoffe, das hilft!

    
templatetypedef 08.01.2012, 21:26
quelle
2

Die Referenzzählung hat die folgenden Einschränkungen:

  • Es ist SEHR schlecht für Multithreading-Leistung (im Grunde muss jede Zuweisung einer Objektreferenz geschützt sein).
  • Sie können Zyklen nicht automatisch freigeben
gpeche 08.01.2012 21:25
quelle
2

Weil es nicht streng nach Referenzzählung funktioniert.

Betrachten Sie kreisförmige Referenzen, die nicht mehr vom "root" der Anwendung erreichbar sind.

Zum Beispiel:

APP hat einen Verweis auf SOME_SCREEN

SOME_SCREEN hat einen Verweis auf SOME_CHILD

SOME_CHILD hat einen Verweis auf SOME_SCREEN

jetzt, APP löscht den Verweis auf SOME_SCREEN .

In diesem Fall hat SOME_SCREEN immer noch einen Verweis auf SOME_CHILD , und SOME_CHILD hat immer noch einen Verweis auf SOME_SCREEN - in diesem Fall funktioniert Ihr Beispiel also nicht.

Nun, andere (Apple mit ARC, Microsoft mit COM, viele andere) haben Lösungen dafür und arbeiten ähnlicher, wie Sie es beschreiben.

Mit ARC müssen Sie Ihre Referenzen mit Stichwörtern wie strong und weak versehen, damit ARC weiß, wie man mit diesen Referenzen umgeht (und zirkuläre Referenzen vermeidet) ... (lesen Sie nicht zu weit in meine spezifischen Beispiel mit ARC, da ARC diese Dinge während des Kompilierungsprozesses vorraussetzt und keine spezifische Laufzeit per se benötigt, so dass es definitiv so ausgeführt werden kann, wie Sie es beschrieben haben, aber mit einigen davon ist es nicht möglich die Eigenschaften von Java. Ich glaube auch, dass COM mehr dem ähnlich ist, wie du es beschreibst ... aber auch das ist nicht frei von irgendwelchen Überlegungen des Entwicklers.

Tatsächlich wäre kein "einfaches" Referenzzählschema jemals ohne eine gewisse Menge an Gedanken durch den Anwendungsentwickler durchführbar (um zirkuläre Referenzen usw. zu vermeiden)

    
Steve 08.01.2012 21:24
quelle
0

Weil der Garbage Collector in modernen JVMs keine Referenzen mehr zählt. Dieser Algorithmus wird verwendet, um zu lehren, wie GC funktioniert, aber er war sowohl ressourcenintensiv als auch fehleranfällig (z. B. zyklische Abhängigkeiten).

    
Tomasz Nurkiewicz 08.01.2012 21:24
quelle
0

weil der Garbage Collector in Java auf copying collector für 'young generation' Objekte basiert und mark and sweep für 'tenure generations' Objekte.

Ressourcen von: Ссылка

    
amit 08.01.2012 21:26
quelle