Heim  >  Artikel  >  Java  >  Java-Garbage-Collection-Mechanismus

Java-Garbage-Collection-Mechanismus

高洛峰
高洛峰Original
2017-02-27 15:28:371050Durchsuche

Ausführliche Erklärung des Java-Garbage-Collection-Mechanismus

Auf den ersten Blick sollte die Aufgabe der Garbage Collection genau das sein, was der Name vermuten lässt: Müll finden und entfernen. Tatsächlich ist es genau das Gegenteil. Die Garbage Collection verfolgt alle Objekte, die noch verwendet werden, und markiert die verbleibenden Objekte als Müll. Schauen wir uns vor diesem Hintergrund genauer an, wie dieses automatisierte Speicherrecycling namens „Garbage Collection“ in der JVM implementiert wird.

Manuelle Speicherverwaltung

Bevor wir die moderne Version der Speicherbereinigung einführen, werfen wir einen kurzen Blick auf die Tage, als Speicher explizit manuell zugewiesen und freigegeben werden musste. Wenn Sie vergessen, den Speicher freizugeben, kann dieser Speicher nicht wiederverwendet werden. Dieser Speicher ist belegt, wird aber nicht genutzt. Dieses Szenario wird als Speicherverlust bezeichnet.

Das Folgende ist ein einfaches Beispiel für die manuelle Speicherverwaltung, geschrieben in C:

int send_request() {
  size_t n = read_size();
  int *elements = malloc(n * sizeof(int));

  if(read_elements(n, elements) < n) {
    // elements not freed!
    return -1;
  }

  // …

  free(elements)
  return 0;
}

Wie Sie sehen, können Sie es leicht vergessen um den Speicher freizugeben. Früher waren Speicherlecks ein sehr häufiges Problem. Sie können sie nur bekämpfen, indem Sie Ihren Code ständig korrigieren. Daher besteht Bedarf an einer eleganteren Möglichkeit, ungenutzten Speicher automatisch freizugeben, um die Möglichkeit menschlicher Fehler zu verringern. Dieser automatisierte Prozess wird auch Garbage Collection (kurz GC) genannt.

Intelligente Zeiger

Eine frühe Implementierung der automatischen Garbage Collection ist die Referenzzählung. Sie wissen, wie oft auf jedes Objekt verwiesen wurde. Wenn der Zähler 0 erreicht, kann das Objekt sicher recycelt werden. Der Shared Pointer von C++ ist ein sehr bekanntes Beispiel:

int send_request() {
  size_t n = read_size();
  stared_ptr<vector<int>> elements 
       = make_shared<vector<int>&gt();

  if(read_elements(n, elements) < n) {
    return -1;
  }

  return 0;
}

Der von uns verwendete Sharedptr zeichnet auf, wie oft auf dieses Objekt verwiesen wird. Die Anzahl wird um eins erhöht, wenn Sie sie an eine andere Person weitergeben, und um eins verringert, wenn sie den Gültigkeitsbereich verlässt. Sobald diese Anzahl 0 erreicht, löscht sharedptr automatisch den zugrunde liegenden entsprechenden Vektor. Natürlich ist dies nur ein Beispiel, da einige Leser darauf hingewiesen haben, dass dies in der Realität wahrscheinlich nicht der Fall sein wird, aber als Demonstration reicht es aus.

Automatische Speicherverwaltung

Im obigen C++-Code müssen wir auch explizit angeben, dass wir die Speicherverwaltung verwenden müssen. Was würde also passieren, wenn alle Objekte diesen Mechanismus nutzen würden? Das ist so praktisch, dass Entwickler nicht über die Bereinigung des Speichers nachdenken müssen. Die Laufzeit erkennt automatisch, welcher Speicher nicht mehr verwendet wird und gibt ihn frei. Mit anderen Worten: Der Müll wird automatisch recycelt. Der Garbage Collector der ersten Generation wurde 1959 in Lisp eingeführt und die Technologie hat sich bis heute weiterentwickelt.

Referenzzählung

Die Idee, die wir gerade mit dem gemeinsamen Zeiger von C++ demonstriert haben, kann auf alle Objekte angewendet werden. Viele Sprachen wie Perl, Python und PHP verwenden diesen Ansatz. Dies lässt sich leicht mit einem Bild erklären:

Die grüne Wolke stellt die im Programm noch verwendeten Objekte dar. Aus technischer Sicht ist dies ein bisschen wie eine lokale Variable in einer ausgeführten Methode oder eine statische Variable. Die Situation kann je nach Programmiersprache unterschiedlich sein, daher ist dies nicht unser Schwerpunkt.

Die blauen Kreise stellen Objekte im Speicher dar, und Sie können sehen, wie viele Objekte darauf verweisen. Objekte in grauen Kreisen werden von niemandem mehr referenziert. Daher handelt es sich um Müllobjekte, die vom Garbage Collector bereinigt werden können.

Sieht gut aus, oder? Ja, aber es gibt einen großen Fehler. Es ist leicht, dass einige isolierte Ringe auftauchen. Die darin enthaltenen Objekte gehören keiner Domäne an, sie verweisen jedoch aufeinander, was zu einer Referenznummer ungleich Null führt. Hier ist ein Beispiel:

Wie Sie sehen können, ist der rote Teil tatsächlich ein Müllobjekt, das von der Anwendung nicht mehr verwendet wird. Aufgrund eines Fehlers bei der Referenzzählung kommt es zu einem Speicherverlust.

Es gibt mehrere Möglichkeiten, dieses Problem zu lösen, z. B. die Verwendung spezieller „schwacher“ Referenzen oder die Verwendung eines speziellen Algorithmus zum Recyceln von Zirkelreferenzen. Die zuvor erwähnten Sprachen wie Perl, Python und PHP verwenden alle ähnliche Methoden zum Recyceln von Zirkelverweisen, dies würde jedoch den Rahmen dieses Artikels sprengen. Wir werden die von der JVM verwendete Methode im Detail vorstellen.

Löschung markieren

Zunächst sollte die Definition der Objekterreichbarkeit durch die JVM klarer sein. Es ist nicht mehr so ​​vage wie zuvor mit einer grünen Wolke, sondern hat eine sehr klare und spezifische Definition des Garbage Collection Roots-Objekts (Garbage Collection Roots):

  • Lokale Variablen

  • Aktivitätsthread

  • Statische Felder

  • JNI-Referenz

  • Andere (wird später besprochen)

JVM zeichnet alle erreichbaren (Überlebens-)Objekte über den Markierungs- und Löschalgorithmus auf und stellt gleichzeitig sicher, dass der Speicher nicht erreichbarer Objekte wiederverwendet werden kann. Dies besteht aus zwei Schritten:

  • Markieren bezieht sich auf das Durchlaufen aller erreichbaren Objekte und das anschließende Aufzeichnen der Informationen dieser Objekte im lokalen Speicher

  • Löschen Stellt sicher, dass die Speicheradresse des nicht erreichbaren Objekts bei der nächsten Speicherzuweisung verwendet werden kann.

Verschiedene GC-Algorithmen in JVM, wie Parallel Scavenge, Parallel Mark+Copy und CMS, sind alle unterschiedliche Implementierungen dieses Algorithmus, aber jede Stufe ist konzeptionell etwas anders, sie sind immer noch gleich Entspricht zu den beiden oben genannten Schritten.

Das Wichtigste an dieser Implementierung ist, dass es keine durchgesickerten Objektschleifen mehr gibt:

Der Nachteil besteht darin, dass der Anwendungsthread angehalten werden muss, um das Recycling abzuschließen, wenn die Referenz erhalten bleibt Wenn Sie sich ändern, können Sie nicht zählen. Die Situation, in der die Anwendung angehalten wird, damit die JVM ihre Aufgaben erledigen kann, wird auch als „Stop The World Pause“ (STW) bezeichnet. Es gibt viele Möglichkeiten, diese Pause auszulösen, aber die Garbage Collection ist wahrscheinlich die häufigste.

Vielen Dank fürs Lesen, ich hoffe, es kann Ihnen helfen, vielen Dank für Ihre Unterstützung dieser Website!

Weitere Artikel zum Java-Garbage-Collection-Mechanismus finden Sie auf der chinesischen PHP-Website!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn