(點選上方公眾號,可快速關註)
來源:佔小狼,
www.jianshu.com/p/0f1f5adffdc1
為解決CMS演演算法產生空間碎片和其它一系列的問題缺陷,HotSpot提供了另外一種垃圾回收策略,G1(Garbage First)演演算法,透過引數-XX:+UseG1GC來啟用,該演演算法在JDK 7u4版本被正式推出,官網對此描述如下:
The Garbage-First (G1) collector is a server-style garbage collector, targeted for multi-processor machines with large memories. It meets garbage collection (GC) pause time goals with a high probability, while achieving high throughput. The G1 garbage collector is fully supported in Oracle JDK 7 update 4 and later releases. The G1 collector is designed for applications that:
-
Can operate concurrently with applications threads like the CMS collector.
-
Compact free space without lengthy GC induced pause times.
-
Need more predictable GC pause durations.
-
Do not want to sacrifice a lot of throughput performance.
-
Do not require a much larger Java heap.
G1垃圾收集演演算法主要應用在多CPU大記憶體的服務中,在滿足高吞吐量的同時,竟可能的滿足垃圾回收時的暫停時間,該設計主要針對如下應用場景:
-
垃圾收集執行緒和應用執行緒併發執行,和CMS一樣
-
空閑記憶體壓縮時避免冗長的暫停時間
-
應用需要更多可預測的GC暫停時間
-
不希望犧牲太多的吞吐效能
-
不需要很大的Java堆 (翻譯的有點虛,多大才算大?)
堆記憶體結構
1、以往的垃圾回收演演算法,如CMS,使用的堆記憶體結構如下:
-
新生代:eden space + 2個survivor
-
老年代:old space
-
持久代:1.8之前的perm space
-
元空間:1.8之後的metaspace
這些space必須是地址連續的空間。
2、在G1演演算法中,採用了另外一種完全不同的方式組織堆記憶體,堆記憶體被劃分為多個大小相等的記憶體塊(Region),每個Region是邏輯連續的一段記憶體,結構如下:
每個Region被標記了E、S、O和H,說明每個Region在執行時都充當了一種角色,其中H是以往演演算法中沒有的,它代表Humongous,這表示這些Region儲存的是巨型物件(humongous object,H-obj),當新建物件大小超過Region大小一半時,直接在新的一個或多個連續Region中分配,並標記為H。
Region
堆記憶體中一個Region的大小可以透過-XX:G1HeapRegionSize引數指定,大小區間只能是1M、2M、4M、8M、16M和32M,總之是2的冪次方,如果G1HeapRegionSize為預設值,則在堆初始化時計算Region的實踐大小,具體實現如下:
預設把堆記憶體按照2048份均分,最後得到一個合理的大小。
GC樣式
G1中提供了三種樣式垃圾回收樣式,young gc、mixed gc 和 full gc,在不同的條件下被觸發。
young gc
發生在年輕代的GC演演算法,一般物件(除了巨型物件)都是在eden region中分配記憶體,當所有eden region被耗盡無法申請記憶體時,就會觸發一次young gc,這種觸發機制和之前的young gc差不多,執行完一次young gc,活躍物件會被複製到survivor region或者晉升到old region中,空閑的region會被放入空閑串列中,等待下次被使用。
mixed gc
當越來越多的物件晉升到老年代old region時,為了避免堆記憶體被耗盡,虛擬機器會觸發一個混合的垃圾收集器,即mixed gc,該演演算法並不是一個old gc,除了回收整個young region,還會回收一部分的old region,這裡需要註意:是一部分老年代,而不是全部老年代,可以選擇哪些old region進行收集,從而可以對垃圾回收的耗時時間進行控制。
那麼mixed gc什麼時候被觸發?
先回顧一下cms的觸發機制,如果添加了以下引數:
-XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly
當老年代的使用率達到80%時,就會觸發一次cms gc。相對的,mixed gc中也有一個閾值引數 -XX:InitiatingHeapOccupancyPercent,當老年代大小佔整個堆大小百分比達到該閾值時,會觸發一次mixed gc.
mixed gc的執行過程有點類似cms,主要分為以下幾個步驟:
-
initial mark: 初始標記過程,整個過程STW,標記了從GC Root可達的物件
-
concurrent marking: 併發標記過程,整個過程gc collector執行緒與應用執行緒可以並行執行,標記出GC Root可達物件衍生出去的存活物件,並收集各個Region的存活物件資訊
-
remark: 最終標記過程,整個過程STW,標記出那些在併發標記過程中遺漏的,或者內部取用發生變化的物件
-
clean up: 垃圾清除過程,如果發現一個Region中沒有存活物件,則把該Region加入到空閑串列中
full gc
如果物件記憶體分配速度過快,mixed gc來不及回收,導致老年代被填滿,就會觸發一次full gc,G1的full gc演演算法就是單執行緒執行的serial old gc,會導致異常長時間的暫停時間,需要進行不斷的調優,盡可能的避免full gc.
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能