JVM調優必備理論知識-GCCollector

鮑春海發表於2020-10-26

 


準備知識:

存活性分析(怎麼找到垃圾):

1.Reference Count引用計數

物件被引用,計數器加一,如果數值減到0,就判斷這個物件是垃圾,可以被回收。Objective-C使用這種方式

                    圖1-1

2.Root Searching根可達演算法

像(圖1-2)中A,B,C相互引用的情況,按引用計數都是1,不是垃圾,不會被回收。

但沒有其他物件引用這3個物件,在java中是可被回收的垃圾

                                 圖1-2

根可達演算法:簡單地說,如果可以從任何一個已經定義的變數開始,直接或者通過其他物件的引用來訪問到某個物件,則該物件是可達的

                                                                                                    圖1-3

根物件:

  • 執行緒變數:從一個main方法執行開始,main執行緒棧中呼叫到的其他方法,main執行緒棧中訪問到的物件
  • 靜態變數:方法區中的類靜態屬性引用的物件
  • 常量池:方法區中的常量引用的物件
  • JNI指標:本地方法棧中JNI(Native方法)的引用的物件

主流程式語言均使用根可達演算法


 

一、常用的垃圾回收演算法

一)Mark-Sweep(標記清除演算法)

                                          圖2-1

標記階段:通過根可達演算法,將沿途的物件進行標記,標記為存活物件,其他未被標記的物件就是可回收物件。

清除階段:將全部物件掃描一遍,沒有標記的物件都進行清除。

特點:

演算法相對簡單,在存活物件比較多的情況下,效率比較高

掃描2遍,效率偏低

容易產生碎片

標記清除演算法不適合Eden區

二)Copying(拷貝演算法)

                                            圖2-2

拷貝演算法:準備一塊新空間,將存活物件都複製到新空間中。然後將舊空間中的物件全部回收。

特點:

適合存活物件較少的情況,適合Eden區

相對於複製清楚演算法,節省了存在大量物件時重新掃描一遍記憶體的開銷,且不會產生碎片

但是,增加了記憶體消耗,實際記憶體使用率僅50%

HotSpot虛擬機器的Serial、ParNew等新生代收集器均採用半區複製分代策略

三)Mark-Compact(標記壓縮)

                                            圖2-3

標記階段(與標記清除演算法相同):過根可達演算法,將沿途的物件進行標記,標記為存活物件,其他未被標記的物件就是可回收物件。

壓縮階段:

  1. 遍歷堆, 將所有物件通過計算得到新的地址並儲存
  2. 遍歷堆, 將所有子物件的地址更新為新的地址, 同時更新根集合中的指標.
  3. 遍歷堆, 將物件集體遷移. 指標的問題都解決了, 可以將物件搬到新家了.

常用實現演算法:Lisp2演算法、Two-Finger演算法

特點:

不會產生碎片,不會產生記憶體減半的問題

掃描2次,需要移動物件,效率偏低

二、垃圾回收器的分代

ZGC之前的演算法存在分代,ZGC及以後的演算法不在進行分代

垃圾回收器分代,分為邏輯分代和物理分代

其中,G1僅在邏輯分代,物理不分代

                                                   圖3-1

物理分代:

區分為:Young(新生代)    Old(老年代)  其中新生代:老年代=1:3

新生代又可以細分為:Eden區,Survivor區(分為survivor0,survivor1,也是常說的from,to)

按垃圾回收發生的範圍:

  • 新生代收集Minor GC/Young GC:指目標只是新生代的垃圾收集。
  • 老年代收集Major GC/Old GC:指目標只是老年代的垃圾收集。
  • 整堆收集(Full GC):收集整個Java堆和方法區的垃圾收集。

新建立的物件都會被分配到Eden區(一些大物件特殊處理),這些物件經過第一次Minor GC後,如果仍然存活,將會被移到Survivor區。物件在Survivor區中每熬過一次Minor GC,年齡就會增加1歲,當它的年齡增加到一定程度時,就會被移動到年老代中

當Survivor空間不足以容納一次Minor GC之後存活的物件時,就需要依賴其他記憶體區域(實
際上大多就是老年代)進行分配擔保(Handle Promotion)

新生代 + 老年代 + 永久代(1.7)Perm Generation/ 後設資料區(1.8) Metaspace
   1. 永久代 後設資料 - Class
   2. 永久代必須指定大小限制 ,後設資料可以設定,也可以不設定,無上限(受限於實體記憶體)
   3. 字串常量 1.7 - 永久代,1.8 - 堆
   4. MethodArea邏輯概念 - 永久代、後設資料

三、常用的垃圾回收器

 

                                      圖4-1                                                                                         圖4-2

  1. Serial 年輕代          序列回收
  2. PS 年輕代               並行回收(jdk1.8預設)
  3. ParNew 年輕代      配合CMS的並行回收
  4. SerialOld 
  5. ParallelOld

Serial:當工作時所有工作執行緒都停止,當工作的時候斷開的執行緒則是垃圾,如果突然加入Serial,則停止,進行垃圾清理

safe point: 執行緒停止

Serial Old:用在老年代,使用標記壓縮的演算法,用的也是單執行緒

Parallel Scavenge:jdk1.8預設垃圾回收器

Parallel Old:標記壓縮演算法

ParNew: Parallel New,在Parallel Scavenge的基礎上做了一些增強,以便可以配合CMS使用

CMS

                                                 圖4-3

  1. 初始標記:標記根節點
  2. 併發標記:工作執行緒和標記同事進行(CMS耗時最長的階段)
  3. 重新標記:併發標記過程中重新產生的垃圾,重新標記一次
  4. 併發清理:併發清理階段會產生浮動垃圾

ConcurrentMarkSweep 老年代 併發的, 垃圾回收和應用程式同時執行,降低STW的時間(200ms)
CMS問題比較多,所以現在沒有一個版本預設是CMS,只能手工指定
CMS既然是MarkSweep

  1. 就一定會有碎片化的問題,碎片到達一定程度,
  2. CMS的老年代分配物件分配不下的時候,使用SerialOld 進行老年代回收 

併發標記的演算法

CMS使用:三色標記演算法+incremental Update演算法

G1:三色標記演算法+SATB演算法,主要配合他的Rset來進行

ZGC:用的是顏色指標

相關文章