大多數JVM將堆分為三代 - 年輕一代(YG),老一代(OG)和永久一代(也稱為終身代)。這些堆後面是什麼?
實證研究表明,大多數所建立的物件的壽命都很短 -
資源
正如您所看到的那樣,隨著時間的推移越來越多的物件被分配,倖存的位元組數變得越來越少(通常)。Java物件的死亡率很高。
下面來看一個簡單的例子。Java中的String
類是不可變的。每次需要更改String
物件的內容時,都必須完全建立一個新物件。假設在迴圈中對字串進行了1000
次更改,如下面的程式碼所示 -
String str = 「G11 GC」;
for(int i = 0 ; i < 1000; i++) {
str = str + String.valueOf(i);
}
在每個迴圈中,需要建立一個新的字串物件,並且在上一次疊代期間建立的字串變得無用(即,它不被任何參照)。該物件的T
生命週期只是一次疊代 - 它們將立即被GC收集。這種短壽命的物件儲存在堆的年輕一代(YG)區域。從年輕一代(YG)收集物件的過程稱為次要垃圾收集,它總是導致「停止世界」暫停。
當年輕一代(YG)被填滿時,GC會進行小規模的垃圾收集。丟棄死物件,並將活動物件移動到老一代(OG)。應用程式執行緒在此過程中停止。
在這裡,我們可以看到這種代設計提供的優勢。年輕一代只是堆的一小部分,很快就會被填滿。但處理它比處理整個堆所花費的時間要少很多。所以,在這種情況下,「停止世界」的停頓要短得多,儘管更頻繁。我們應該始終瞄準較長時間的暫停,即使它們可能更頻繁。我們將在本教學的後續部分詳細討論這個問題。
年輕一代分為兩個空間 - survivor 和 eden 空間。在收集 eden期間幸存下來的物件被移動到survivor空間,survivor空間中存活的物件移動到老一代。年輕一代在被收集時被壓縮。
隨著物件移動到舊一代,它最終會被填滿,並且必須被收集和壓縮。不同的演算法採用不同的方法。它們中的一些停止了應用程式執行緒(由於老一代與年輕代相比非常大,因此導致長時間「停止世界」暫停),而其中一些執行緒在應用程式執行緒繼續執行時同時執行。此過程稱為完整GC。兩個這樣的收集器是CMS和G1。
現在讓我們詳細分析這些演算法。
序列GC
它是用戶端類計算機上的預設GC(單處理器計算機或32b JVM,Windows)。通常,GC是多執行緒的,但序列GC不是。它有一個單獨的執行緒來處理堆,並且它會在執行次要GC或主要GC時停止應用程式執行緒。可以通過指定標誌來命令JVM使用此GC: -XX:+ UseSerialGC
。如果我們希望它使用一些不同的演算法,請指定演算法名稱。請注意,舊一代在主要GC期間完全壓縮。
吞吐量GC
此GC在64b JVM和多CPU計算機上是預設的。與序列GC不同,它使用多個執行緒來處理年輕一代。因此,GC也稱為並行收集器。我們可以通過使用標誌來命令我們的JVM使用此收集器:-XX:+ UseParallelOldGC
或-XX:+ UseParallelGC
(從JDK 8開始)。應用程式執行緒在執行主要或次要垃圾回收時停止。與序列收集器一樣,它在主要GC期間完全壓縮年輕一代。
吞吐量GC收集YG和OG。當伊甸園已經填滿時,收集器會將活動物件從其中彈出到OG或其中一個倖存者空間(下圖中的SS0和SS1)。丟棄死物件以釋放它們佔用的空間。
在YG的GC之前
在YG的GC之後
在完整GC期間,吞吐量收集器會清空整個YG,SS0和SS1。操作後,OG僅包含活動物件。我們應該注意,上述兩個收集器在處理堆時都會停止應用程式執行緒。在主要GC期間長時間「停止世界」暫停。接下來的兩個演算法旨在消除它們,代價是更多的硬體資源 -
CMS收集器
它代表’並行標記掃描’。它的功能是它使用一些後台執行緒定期掃描舊代,並清除死物件。但在次要GC期間,應用程式執行緒將停止。但是,暫停非常小。這使CMS成為低暫停收集器。
在執行應用程式執行緒時,此收集器需要額外的CPU時間來掃描堆。此外,後台執行緒只收集堆並且不執行任何壓縮。它們可能導致堆變得支離破碎。隨著這種情況的繼續,在一段時間之後,CMS將停止所有應用程式執行緒並使用單個執行緒壓縮堆。使用以下JVM引數告訴JVM使用CMS收集器 -
XX:+UseConcMarkSweepGC -XX:+UseParNewGC
作為JVM引數告訴它使用CMS收集器。
在GC之前
在GC之後
請注意,該集合同時進行。
G1 GC
該演算法通過將堆分成多個區域來工作。與CMS收集器一樣,它在執行次要GC時停止應用程式執行緒,並使用後台執行緒來處理舊代,同時保持應用程式執行緒的執行。由於它將舊一代劃分為區域,因此在將物件從一個區域移動到另一個區域的同時不斷壓縮它們。因此,碎片是最小的。可以使用標誌:XX:+ UseG1GC
指示JVM使用此演算法。與CMS一樣,它還需要更多的CPU時間來處理堆並同時執行應用程式執行緒。
該演算法設計用於處理較大的堆(>4G),它分成許多不同的區域。其中一些地區包括年輕一代,其餘地區包括舊年代。使用傳統方式清除YG - 停止所有應用程式執行緒以及所有仍然存在於舊代或倖存者空間的物件。
請注意,所有GC演算法都將堆分為YG和OG,並使用STWP清除YG。這個過程通常非常快。