JVM-GC算法及垃圾收集器超級詳細解讀(520 是什麼? 不存在!)

數哥:今天 05-20 據說這是一個節日?
我:不知道
數哥:那你今天怎麼過?
我:擼起袖子-擼代碼
在這裏插入圖片描述

一、GC算法

1、標記-清除算法

描述:

  1. 標記。從根結點(GC root)出發遍歷對象,對訪問過的對象打上標記,表示該對象可達。
  2. 清除。對那些沒有標記的對象進行回收,這樣使得不能利用的空間能夠重新被利用。

優點

  • 實現簡單
  • 不移動對象,

缺點:

  • 清理出來的空閒內存是不連續的
  • 效率比較低(遞歸與全堆對象遍歷),而且在進行GC的時候,需要停止應用程序

在這裏插入圖片描述

2、標記-壓縮算法(標記-整理)

描述:

  1. 從GCroot 開始遍歷,標記活動的對象
  2. 清除沒有被標記的空間
  3. 對空間碎片重排,變緊湊

優點:

  • 無內存碎片
  • 相對內存複製 不會浪費內存空間

缺點:

  • 壓縮花費計算成本大

在這裏插入圖片描述

3、複製算法

描述:

  1. 在from區中,從GCroot 開始遍歷,標記活動的對象
  2. 清除沒有被標記的空間
  3. 將from區中 存活的對象空間 copy到 to 區
  4. 將from區和to區的 指針表示 swap

優點

  • 優秀的吞吐量
  • 可實現高速分配
  • 不會發生碎片化
  • 與緩存兼容

缺點:

  • 堆使用率低下
  • 不兼容保守式GC算法

在這裏插入圖片描述

4、分代收集算法

分代算法主要就是基於以上三種算法 ”因才施教“;

不同的區域使用 適合的算法;

具體的各種垃圾收集器 就是很好的實現

二、垃圾收集器

1.串行收集器

1)Serial收集器
特點:

​ 1、用於新生代

​ 2、使用複製算法

​ 3、單線程運行-進行垃圾收集時,暫停所有工作線程,即"Stop The World"

2)Serial-old
特點:

​ 1、用於老年代

​ 2、使用標記整理算法

​ 3、單線程運行-進行垃圾收集時,暫停所有工作線程,即"Stop The World"

時序圖

在這裏插入圖片描述

設置:"-XX:+UseSerialGC":添加該參數來顯式的使用串行垃圾收集器;

2. 並行收集器

1)ParNew

在這裏插入圖片描述

參數設置:

“-XX:+UseParNewGC”:強制指定使用ParNew;
“-XX:ParallelGCThreads”:指定垃圾收集的線程數量,ParNew默認開啓的收集線程與CPU的數量相同;

2)Parallel收集器

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-297GGyc6-1589975958770)(C:%5CUsers%5Cbeauty%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20200520191636802.png)]

Parallel Scavenge收集器類似ParNew收集器,Parallel收集器更關注系統的吞吐量;新生代使用"複製"算法,老年代使用"標記-壓縮"

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和"標記壓縮"算法

參數設置:

-XX:+UseParallelGC 使用Parallel收集器+老年代串行

-XX:+UseParallelOldGC 使用Parallel收集器+老年代並行

3)CMS收集器(14版本 已經移除)

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器;

老年代收集器(新生代使用ParNew)老年代收集器(新生代使用ParNew);

初始標記、重新標記這兩個步驟仍然需要"Stop The World";

在這裏插入圖片描述

優點:併發收集、低停頓
缺點:產生大量空間碎片、併發階段會降低吞吐量

參數設置:

-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:+UseCMSCompactAtFullCollection "Full GC"後,進行一次碎片整理,整理過程是獨佔的,會引起停頓時間變長
-XX:+CMSFullGCsBeforeCompaction 設置進行幾次Full GC後,進行一次碎片整理
-XX:ParallelCMSThreads 設定CMS的線程數量(一般情況約等於可用CPU數量)

4)G1收集器

G1收集器有以下特點:

  1. 空間整合,G1收集器採用"標記-壓縮"算法,不會產生內存空間碎片。分配大對象時不會因爲無法找到連續空間而提前觸發下一次GC。
  2. 可預測停頓,這是G1的另一大優勢,降低停頓時間是G1和CMS的共同關注點,但G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度爲N毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒,這幾乎已經是實時Java(RTSJ)的垃圾收集器的特徵了。

與其他垃圾收集器的區別:

上面提到的垃圾收集器,收集的範圍都是整個新生代或者老年代;使用G1收集器時,Java堆的內存佈局與其他收集器有很大差別,它將整個Java堆劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,新生代和老年代不再是物理隔閡,它們都是一部分(可以不連續)Region的集合

收集步驟:

  1. 標記階段,首先初始標記(Initial-Mark),這個階段是停頓的(Stop the World Event),並且會觸發一次普通Mintor GC,對應GC log:GC pause (young) (inital-mark)
  2. Root Region Scanning,程序運行過程中會回收survivor區(存活到老年代),這一過程必須在young GC之前完成。
  3. Concurrent Marking,在整個堆中進行併發標記(和應用程序併發執行),此過程可能被young GC中斷。在併發標記階段,若發現區域對象中的所有對象都是垃圾,那個這個區域會被立即回收(圖中打X)。同時,併發標記過程中,會計算每個區域的對象活性(區域中存活對象的比例)。
  4. Remark, 再標記,會有短暫停頓(STW)。再標記階段是用來收集 併發標記階段 產生新的垃圾(併發階段和應用程序一同運行);G1中採用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB)。
  5. Copy/Clean up,多線程清除失活對象,會有STW。G1將回收區域的存活對象拷貝到新區域,清除Remember Sets,併發清空回收區域並把它返回到空閒區域鏈表中。
  6. 複製/清除過程後。回收區域的活性對象已經被集中回收到深褐色和深綠色區域,未回收的部分保持原位置。

在這裏插入圖片描述

在這裏插入圖片描述

5)ZGC (11版本 新增)

在JDK 11當中,加入了實驗性質的ZGC。它的回收耗時平均不到2毫秒。它是一款低停頓高併發的收集器。

ZGC幾乎在所有地方併發執行的,除了初始標記的是STW的。所以停頓時間幾乎就耗費在初始標記上,這部分的實際是非常少的。那麼其他階段是怎麼做到可以併發執行的呢?

ZGC主要新增了兩項技術,一個是着色指針Colored Pointer,另一個是讀屏障Load Barrier

着色指針Colored Pointer
ZGC利用指針的64位中的幾位表示Finalizable、Remapped、Marked1、Marked0(ZGC僅支持64位平臺),以標記該指向內存的存儲狀態。相當於在對象的指針上標註了對象的信息。注意,這裏的指針相當於Java術語當中的引用。

在這個被指向的內存發生變化的時候(內存在Compact被移動時),顏色就會發生變化。

在G1的時候就說到過,Compact階段是需要STW,否則會影響用戶線程執行。那麼怎麼解決這個問題呢?

讀屏障Load Barrier 由於着色指針的存在,在程序運行時訪問對象的時候,可以輕易知道對象在內存的存儲狀態(通過指針訪問對象),若請求讀的內存在被着色了。那麼則會觸發讀屏障。讀屏障會更新指針再返回結果,此過程有一定的耗費,從而達到與用戶線程併發的效果。

常用的垃圾收集器組合

新生代 老年代
Serial Serial Old
Serial CMS + Serial Old
ParNew CMS
ParNew Serial Old
Parallel Scavenge Serial Old
Parallel Scavenge Parallel Old
G1 G1

個人水平有限,如有問題,歡迎大家留言指出,虛心接受,及時更正

如果大家覺得,還可以,煩請點贊收藏,謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章