Heim  >  Artikel  >  Java  >  Forschung zum Recyclingmechanismus in der Java Virtual Machine

Forschung zum Recyclingmechanismus in der Java Virtual Machine

一个新手
一个新手Original
2017-09-07 15:38:411636Durchsuche


1: Überblick

Apropos Garbage Collection (Garbage Collection, GC): Viele Leute werden es natürlich mit Java in Verbindung bringen. In Java müssen sich Programmierer nicht um die dynamische Speicherzuweisung und Garbage Collection kümmern. Wie der Name schon sagt, dient die Garbage Collection dazu, den von Garbage belegten Speicherplatz freizugeben. Dies alles wird der JVM überlassen. Dieser Artikel beantwortet hauptsächlich drei Fragen:

1. Welcher Speicher muss recycelt werden? (Welche Gegenstände können als „Müll“ betrachtet werden)
2. Wie recyceln? (Häufig verwendete Müllsammelalgorithmen)
3. Welche Werkzeuge werden zum Recycling verwendet? (Garbage Collector)

2. JVM-Müllbestimmungsalgorithmus

Zu den häufig verwendeten Müllbestimmungsalgorithmen gehören: Referenzzählalgorithmus und Erreichbarkeitsanalysealgorithmus.

1. Referenzzählalgorithmus

Java ist über Referenzen mit Objekten verknüpft, was bedeutet, dass Sie dies über Referenzen tun müssen, wenn Sie ein Objekt bedienen möchten. Immer wenn ein Verweis auf das Objekt vorhanden ist, wird der Zählerwert um 1 erhöht. Wenn der Verweis abläuft, kann der Zählerwert zu keinem Zeitpunkt um 1 verringert werden mehr, das heißt, Zeigt an, dass das Objekt als „Müll“ zum Recycling betrachtet werden kann.

Der Referenzzähleralgorithmus ist einfach zu implementieren und hocheffizient; er kann jedoch das Problem der Zirkelverweise nicht lösen (Objekt A verweist auf Objekt B, Objekt B verweist auf Objekt A, die Objekte A und B jedoch nicht). nicht mehr von anderen Objekten referenziert wird), Gleichzeitig bringt jede Erhöhung und Verringerung des Zählers viel zusätzlichen Overhead mit sich, sodass dieser Algorithmus nach JDK1.1 nicht mehr verwendet wird. Code:

public class Main {    
    public static void main(String[] args) {
        MyTest test1 = new MyTest();
        MyTest test2 = new MyTest();

        test1.obj  = test2;
        test2.obj  = test1;//test1与test2存在相互引用 

        test1 = null;
        test2 = null;

        System.gc();//回收
    }
}

class MyTest{    
    public Object obj = null;
}

Obwohl test1 und test2 schließlich null zugewiesen werden, bedeutet dies, dass auf die Objekte, auf die test1 und test2 zeigen, nicht mehr zugegriffen werden kann. Da sie jedoch aufeinander verweisen, beträgt ihre Referenzanzahl alle Wenn nicht 0, werden sie vom Garbage Collector niemals gesammelt. Nach dem Ausführen des Programms können wir anhand der Speicheranalyse erkennen, dass der Speicher dieser beiden Objekte tatsächlich recycelt wird. Dies zeigt auch, dass die aktuelle Mainstream-JVM den Referenzzähleralgorithmus nicht als Müllermittlungsalgorithmus verwendet.

2. Algorithmus zur Erreichbarkeitsanalyse (Root-Suchalgorithmus)

Der Root-Suchalgorithmus verwendet einige „GC Roots“-Objekte als Ausgangspunkt, sucht von diesen Knoten aus nach unten und sucht nach dem übergebenen Pfad Wird zu einer Referenzkette
(Referenzkette). Wenn ein Objekt nicht durch die Referenzkette von GC Roots verbunden ist, bedeutet dies, dass das Objekt nicht verfügbar ist.

Forschung zum Recyclingmechanismus in der Java Virtual Machine

GC Roots-Objekte umfassen:
a) Objekte, auf die im Stapel der virtuellen Maschine verwiesen wird (lokale Variablentabelle im Stapelrahmen).
b) Das Objekt, auf das die statische Eigenschaft der Klasse im Methodenbereich verweist.
c) Das Objekt, auf das die Konstante im Methodenbereich verweist.
d) Das von JNI referenzierte Objekt (im Allgemeinen native Methode) im nativen Methodenstapel.

Im Erreichbarkeitsanalysealgorithmus sind nicht erreichbare Objekte nicht „notwendig, um zu sterben“. Zu diesem Zeitpunkt befinden sie sich vorübergehend in der „suspendierten“ Phase. Um ein Objekt wirklich für tot zu erklären, sind mindestens zwei Sekundärmarkierungen erforderlich Prozess: Wenn nach der Erreichbarkeitsanalyse festgestellt wird, dass das Objekt keine mit GC Roots verbundene Referenzkette hat, wird es zum ersten Mal markiert und einmal gefiltert. Die Filterbedingung ist, ob das Objekt die Methode finalize() ausführen muss. Wenn das Objekt die finalize()-Methode nicht abdeckt oder die finalize()-Methode von der virtuellen Maschine aufgerufen wurde, behandelt die virtuelle Maschine beide Situationen als „keine Ausführung erforderlich“. Beachten Sie, dass die finalize()-Methode eines Objekts vom System nur einmal automatisch ausgeführt wird.

Wenn festgestellt wird, dass dieses Objekt die finalize()-Methode ausführen muss, wird dieses Objekt in eine Warteschlange namens F-Queue gestellt und später automatisch von einer virtuellen Maschine erstellt. Der Prioritäts-Finalizer-Thread führt es aus. Die sogenannte „Ausführung“ bedeutet hier, dass die virtuelle Maschine diese Methode auslöst, aber nicht verspricht, auf den Abschluss der Ausführung zu warten. Der Grund dafür ist, dass ein Objekt in der finalize()-Methode langsam oder unendlich ausgeführt wird Wenn eine Schleife auftritt, kann dies dazu führen, dass andere Objekte in der F-Warteschlange dauerhaft warten oder sogar das gesamte Speicherrecyclingsystem abstürzt. Daher bedeutet der Aufruf der finalize()-Methode nicht, dass der Code in der Methode vollständig ausgeführt werden kann.

Die finalize()-Methode ist die letzte Chance für das Objekt, dem Schicksal zu entkommen. Später markiert der GC das Objekt in der F-Warteschlange für einen zweiten kleinen Maßstab erfolgreich in finalize() gerettet Selbst – Verknüpfen Sie sich einfach erneut mit einem beliebigen Objekt in der Referenzkette, weisen Sie sich beispielsweise (dieses Schlüsselwort) einer Klassenvariablen oder Mitgliedsvariablen des Objekts zu, und es wird entfernt, wenn es für markiert wird zum zweiten Mal aus der Sammlung „kurz vor der Wiederverwertung“ entfernt; wenn das Objekt zu diesem Zeitpunkt nicht entkommen ist, dann ist es im Grunde genommen tatsächlich wiederverwertet. Aus dem folgenden Code können wir erkennen, dass finalize() eines Objekts ausgeführt wird, es aber dennoch überleben kann.

/**   
 * 此代码演示了两点:   
 * 1.对象可以在被GC时自我拯救。   
 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次   
 */    public class FinalizeEscapeGC {    

  public static FinalizeEscapeGC SAVE_HOOK = null;    

  public void isAlive() {    
   System.out.println("yes, i am still alive :)");    
  }    

  @Override    
  protected void finalize() throws Throwable {    
   super.finalize();    
   System.out.println("finalize mehtod executed!");    
   FinalizeEscapeGC.SAVE_HOOK = this;    
  }    

  public static void main(String[] args) throws Throwable {    
   SAVE_HOOK = new FinalizeEscapeGC();    

   //对象第一次成功拯救自己    
   SAVE_HOOK = null;    
   System.gc();    
   //因为finalize方法优先级很低,所以暂停0.5秒以等待它    
   Thread.sleep(500);    
   if (SAVE_HOOK != null) {    
    SAVE_HOOK.isAlive();    
   } else {    
    System.out.println("no, i am dead :(");    
   }    

   //下面这段代码与上面的完全相同,但是这次自救却失败了    
   SAVE_HOOK = null;    
   System.gc();    
   //因为finalize方法优先级很低,所以暂停0.5秒以等待它    
   Thread.sleep(500);    
   if (SAVE_HOOK != null) {    
    SAVE_HOOK.isAlive();    
   } else {    
    System.out.println("no, i am dead :(");    
   }    
  }    
}

Laufergebnis:

finalize mehtod executed!    
yes, i am still alive :)    
no, i am dead :(

从运行结果可以看出,SAVE_HOOK对象的finalize()方法确实被GC收集器调用过,且在被收集前成功逃脱了。
另外一个值得注意的地方是,代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败,这是因为任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行,因此第二段代码的自救行动失败了。

三、JVM垃圾回收算法

常用的垃圾回收算法包括:标记-清除算法,复制算法,标记-整理算法,分代收集算法

1、标记—清除算法(Mark-Sweep)(DVM 使用的算法)

标记—清除算法包括两个阶段:“标记”和“清除”。在标记阶段,确定所有要回收的对象,并做标记。清除阶段紧随标记阶段,将标记阶段确定不可用的对象清除。标记—清除算法是基础的收集算法,标记和清除阶段的效率不高,而且清除后回产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间。

Forschung zum Recyclingmechanismus in der Java Virtual Machine

2、复制算法(Copying)

复制算法是把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉。复制算法实现简单,运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率不高。现在的JVM 用复制方法收集新生代,由于新生代中大部分对象(98%)都是朝生夕死的,所以两块内存的比例不是1:1(大概是8:1)。

Forschung zum Recyclingmechanismus in der Java Virtual Machine

3、标记—整理算法(Mark-Compact)

标记—整理算法和标记—清除算法一样,但是标记—整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存。标记—整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代。

Forschung zum Recyclingmechanismus in der Java Virtual Machine

4、分代收集(Generational Collection)

分代收集是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。

四、垃圾收集器

如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。上面说过,各个平台虚拟机对内存的操作各不相同,因此本章所讲的收集器是基于JDK1.7Update14之后的HotSpot虚拟机。这个虚拟机包含的所有收集器如图:

Forschung zum Recyclingmechanismus in der Java Virtual Machine

1、Serial收集器

Serial收集器是最基本、发展历史最悠久的收集器,曾经(在JDK 1.3.1之前)是虚拟机
新生代收集的唯一选择。大家看名字就会知道,这个收集器是一个单线程的收集器,但它
的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,
更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

Forschung zum Recyclingmechanismus in der Java Virtual Machine

2、ParNew收集器

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之
外,其余行为包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:
PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、对
象分配规则、回收策略等都与Serial收集器完全一样,在实现上,这两种收集器也共用了相
当多的代码。

Forschung zum Recyclingmechanismus in der Java Virtual Machine

3. Parallel Scavenge Collector

Forschung zum Recyclingmechanismus in der Java Virtual Machine

Das Merkmal des Parallel Scavenge Collectors ist, dass sein Fokus sich von dem anderer Collectors unterscheidet Durchsatz. Der sogenannte Durchsatz ist das Verhältnis der Zeit, die die CPU damit verbringt, Benutzercode auszuführen, zur gesamten CPU-Zeit, die verbraucht wird, d. h. Durchsatz = Zeit, die Benutzercode ausführt / (Zeit, die Benutzercode ausführt + Garbage-Collection-Zeit). Aufgrund seiner engen Beziehung zum Durchsatz wird der Parallel Scavenge-Kollektor oft als „Durchsatz-zuerst“-Kollektor bezeichnet.

4. Serial Old Collector

Serial Old ist die alte Generation des Serial Collectors. Es ist auch ein Single-Threaded-Collector und verwendet den „Mark-Sort“-Algorithmus. Die Hauptbedeutung dieses Kollektors besteht darin, dass er auch von virtuellen Maschinen im Client-Modus verwendet werden kann. Wenn es sich im Servermodus befindet, hat es zwei Hauptverwendungszwecke: Zum einen dient es der Verwendung mit dem Parallel Scavenge-Kollektor in JDK 1.5 und früheren Versionen [1] und zum anderen dient es als Backup-Plan für den CMS-Kollektor. Wird verwendet, wenn in der gleichzeitigen Sammlung ein ConcurrentMode-Fehler auftritt.

5. Parallel Old Collector

Parallel Old ist die alte Generation des Parallel Scavenge Collectors, der Multithreading und „Mark-Collation“-Algorithmus verwendet.
Dieser Collector wurde nur in JDK 1.6 bereitgestellt.

6. CMS-Kollektor

Forschung zum Recyclingmechanismus in der Java Virtual Machine

CMS-Kollektor (Concurrent Mark Sweep) ist ein Kollektor, der darauf abzielt, die kürzeste Recycling-Pausezeit zu erreichen. Derzeit konzentriert sich ein großer Teil der Java-Anwendungen auf den Servern von Internet-Websites oder B/S-Systemen. Solche Anwendungen legen besonderen Wert auf die Reaktionsgeschwindigkeit des Dienstes und hoffen, dass die Systempausenzeit für Benutzer so kurz wie möglich ist eine bessere Erfahrung.
Der Vorgang ist in 4 Schritte unterteilt, darunter:
a) Anfangsmarkierung (CMS-Anfangsmarkierung)
b) Gleichzeitige Markierung (CMS-Konkurrenzmarkierung)
c) Bemerkung (CMS-Anmerkung)
d) Concurrent Sweep (CMS Concurrent Sweep)

Der CMS-Kollektor hat drei Nachteile:
1 Er reagiert empfindlich auf CPU-Ressourcen. Im Allgemeinen reagieren gleichzeitig ausgeführte Programme empfindlich auf die Anzahl der CPUs
2 und können schwebenden Müll nicht verarbeiten. Während der gleichzeitigen Bereinigungsphase wird der Benutzerthread noch ausgeführt und der zu diesem Zeitpunkt erzeugte Müll kann nicht bereinigt werden.
3 Aufgrund des Mark-Sweep-Algorithmus wird eine große Raumfragmentierung erzeugt.

7. G1-Kollektor

Forschung zum Recyclingmechanismus in der Java Virtual Machine

G1 ist ein Garbage Collector für serverseitige Anwendungen.
Der Betrieb des G1-Kollektors kann grob in die folgenden Schritte unterteilt werden:

a) Erste Markierung (Initial Marking)
b) Gleichzeitige Markierung (Concurrent Marking)
c) Endgültige Markierung (Endgültige Bewertung)
d) Screening und Recycling (Live-Datenzählung und Evakuierung)


Das obige ist der detaillierte Inhalt vonForschung zum Recyclingmechanismus in der Java Virtual Machine. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen 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