G1垃圾回收器

垃圾回收器的發展歷程

file

背景

0一、G1解決的問題

G1垃圾回收器是04年正式提出,12開始正式支持,在17年做爲JDK9默認的垃圾處理器。
filejava

04年的時候,java程序堆的內存愈來愈大,從而致使程序中可存活的活對象愈來愈多,所以GCSTW時間愈來愈長。這是G1要解決的主要問題:STW帶來的停頓時間太長了算法

CMS在此以前效率也很高,但活對象數量一多,STW時間也很長。並且CMS沒法解決內存碎片化的問題。shell

G1還解決的問題是:CMSGC後,沒法compact內存。多線程

0二、G1達成的目標

(1)減小因爲STW而帶來的程序延遲時間,作到僞實時、低延時、可設定目標;
可設定目標是指可以設置GC最大STW停頓的時間,G1會盡可能達成目的,但不必定達成。併發

-XX:MaxGCPauseMillis=N

默認狀況下是250毫秒oracle

(2)解決CMSGC後,沒法壓縮程序內存的問題;app

(3)在JDK9以後,默認的垃圾處理器就是G1;它適用於堆內存較大的狀況下(>4~6G);佈局

G1垃圾回收器

1、G1內存佈局

G1再也不遵循以前的堆中對象的分代排列,而是將堆分紅若干個等大的區域。
file線程

而是變成:
file3d

默認是分紅2048個區域,-XX:G1HeapRegionSize=N 2048

Humongous:當你分配的一個對象超過一半區域的大小時,這個對象就會被放入這個區域。這個區域屬於老年代區域。

2、G1的介紹

G1垃圾回收器再也不回收整個堆,而是選擇一個Collection SetCS)。並且每次GC時,會估計每一個Region中的垃圾比例,優先回收垃圾多的Region。這就爲何被叫作Garbage First算法。這也是爲何G1能夠控制STW停頓時間的緣由。
G1含有三種GC算法:

  • Full young GC:年輕代GC算法:STWParallelCopying
  • 老年代GC算法:Mostly-concurrent markingIncremental compaction
  • Mixed GC:混合GC

3、G1引來的問題

問題描述

G1將年輕代、老年代區域劃分爲許多個小區域,增長在GC判斷對象是否爲垃圾的難度。好比:

  • 老年代對象可能持有年代代的引用(跨代引用)
  • 不一樣的Region間的互相引用
    跨代/跨Region引用

假設在Full young GC時,某個年輕代Region對象可能被老年代的某個對象引用,那麼我在回收這個年輕代Region時,怎麼知道這裏面的對象是否被其餘Region、老年代引用呢?

問題解決

Remembered SetCard Table
file

一、CardTable
每一個Region中分爲不少區域,每一個區域咱們成爲CardTable,對應的就是上述藍色區域;每一個CardTable有多個entry組成。當對應的內存空間發生改變時,就會標記爲dirty

二、RememberedSet
Region1CardTable引用Region2CardTable時,Region2RememberedSet就會記錄對應CardTable中的entry,能夠根據其找到對應的內存區域。

三、解析
當某個內存對應進行賦值是,就是對象的set方法,咱們能夠在這種方法上添加dirty的描述。
這其實就是典型的時間換空間的作法:用額外的空間維護引用信息,這就是佔用5~10%的過多內存佔用。

解決方法的實現

一、Write Barrier介紹
Write barrier是一種向JVM注入的一小段代碼,用於記錄指針變化。好比說object.field = <reference>

JVM開始更新指針時,就通過如下幾步:

  • 標記CardDirty
  • Card存入Dirty Card Queue隊列中

這裏有一個問題:爲何要放在隊列裏,而不是直接去更新RememberedSet呢?
這是由於JVM運行可能會有多個線程並行的修改RememberedSet,這樣就須要花費額外的時間來解決多線程同步問題。而這種更新引用是頻繁的,因此這種額外時間是沒法忍受的。

二、Dirty Card Queue
這個隊列有白、綠、黃、紅四個顏色,表示應用線程往這個隊列聽任務的狀態。

  • White
    表示沒有應用線程往隊列裏聽任務,什麼事都不用幹。

  • Green
    此時Refinement線程開始被激活,開始更新RS-XX:G1ConcRefinementGreenZone=N

  • Yellow
    此時所有的Refinement線程都被激活,來更新RS-XX:G1ConcRefinementYellowZone=N

  • Red
    這個時候,應用線程也開始參與排空隊列的工做。-XX:G1ConcRefinementRedZone=N

4、GC算法的過程

一、Fully young GC

GC的過程

(1)STW
此時會暫停全部堆中的對象,將部分Region拷貝到指定區域。
file

(2)構建Collection Set
fully young GC就是選取全部的EdenSurvivor

(3)掃描GC Roots

(4)更新RememberedSet
排空Dirty Card Queue

(5)Process RS
根據RS找到要GC的對象被哪些對象引用了。

(6)對象拷貝
survivor區域對象的調整。

(7)Reference Processing

額外會作的事

G1記錄每一個階段的時間,用於後期自動調優。好比說會記錄EdenSurvivor的數量和GC時間,後期會根據咱們以前設定的暫停目標來自動調整Region數量。
可是咱們設置暫停目標越短,年輕代的Region數量就越少。但這可能會致使Fully young GC頻繁發生。

二、Old GC

當堆用量達到必定程度時,就會觸發old GC。能夠經過如下參數進行設置:

-XX:InitatingHeapOccpancyPercent=45

old GC有一個很大特色就是併發進行的。但它是如何在堆中不斷變化的狀況下,肯定哪些是要清理的垃圾對象呢?

三色標記算法

這種算法實現了在不暫停應用線程的狀況下進行併發標記,標記過程過以下:
(1)將GC Root對象記錄爲黑色,其直接引用對象記錄爲灰色,並將這些灰色對象放入一個隊列中
file
(2)從隊列取出對象,將其標爲黑色,將其引用對象記錄爲灰色,再放入隊列中
file
(3)直到隊列中無對象爲止
file

三色標記算法的缺點:Lost Object Problem

三色標記算法並無徹底將全部的活對象都標記出來,這就是Lost Object Problem問題。好比說:
(1)剛開始時

file

(2)在即將描述將C標爲灰色的一剎那

file

此時,C依然是活對象,可是已經沒法將其標記了。

(3)結果

file

Lost Object Problem的解決

這種解決辦法仍是經過Write barrier技術來解決。當B.c=null,也就是C指針被刪除時,G1仍是被認爲活對象。

那若是C是新生對象呢?這是老年代GC

Old GC過程

(1)STW
老年代GC會在這個時候,進行一次Fully young GC

(2)恢復應用線程

(3)使用三色標記算法併發標記(init marking

(4)STW

這時候會有一個Remark階段,主要是解決SATBReference processing
還會有一個Cleanup階段,用於回收全爲空的區

(5)恢復應用線程

三、Mixed GC

咱們直到CMS最大的缺點就是沒法進行壓縮操做,而G1就經過Mixed GC解決了這個問題。

Mixed GC沒有固定觸發條件,他是根據Fully young GC收集的信息和咱們配置的時間來決定,是否觸發Mixed GC。它會根據暫停目標,來優先選擇垃圾最多的Old Region來執行。

Mixed GC會選擇若干個Region進行,默認是選擇1/8Old RegionEden RegionSurvivor Region

Mixed GC的過程跟Fully young GC的過程相同,都是:STWParallelCopying

原博客地址

相關文章
相關標籤/搜索