JVM垃圾回收大揭祕

引言

我們都知道在java編程中,我們不需要手動的釋放內存,因爲java有着自動的垃圾回收機制,那麼在java中什麼是垃圾,垃圾回收機制又是怎麼回事,本文將會對JVM的垃圾回收機制做個詳細的介紹。

自動垃圾回收與手動垃圾回收

自動垃圾回收會使得開發效率提高,但在執行中要進行垃圾回收,所以執行效率會降低,而手動處理垃圾則相反,自動垃圾回收會使得編程相對於手動更加容易。

什麼是垃圾

在java中,我們稱沒有任何引用指向的對象或多個對象(循環引用)爲垃圾,這些對象所佔據的內存空間需要垃圾回收機制去自動的回收該部分內存。

怎麼找到垃圾

1.引用計數器(ReferenceCount)
有引用指向對象,則計數器值+1,當引用失效,則-1;
2.根可達性算法(RootSearching)
以某些對象爲根,依次向下搜索,形成條條鏈,當某個對象沒有在鏈上時,說明該對象從根不可達 即爲垃圾。
注:常作根對象: 線程棧變量、靜態變量、常量池、JNI指針(本地方法棧指針)

常見的垃圾回收算法

1.標記清除(mark sweep)-進行兩遍掃描,先找出垃圾然後進行清除,由於垃圾存在不同的位置,會使得內存產生碎片
2.拷貝算法(copying)-將內存分爲兩半,當需要GC時,將有用對象複製到 另一半內存,清除這一半,該算法有個弊端就是浪費內存空間。
3.標記壓縮(mark compact)-相當於標記清除的改進版,會進行碎片整理,這也表明其效率偏低。
注:一般情況下,JVM會將內存分代,不同的代採用不同的垃圾回收器 不同垃圾回收算法進行分代垃圾回收,我們也常稱這種算法爲分代垃圾回收算法

內存分代模型

爲了提升垃圾回收的效率,JVM採用了內存分代模型,將內存分爲了不同的代,新生代(Eden+2個survivor區)、老年代、永久代(MethodArea),不同的代採用不同的垃圾回收器 不同的垃圾回收算法。

  1. MinorGC= YGC 新生代的回收
    MajorGC= FGC 老年代的回收
  2. 新生代採用複製算法,YGC後大多數的對象將被回收,活着的進入s0,再次YGC,活着的Eden+s0區的對象將被複制到s1中,再次YGC,則 Eden+s1 ->s0… 當年齡足夠時(可以設置年齡),對象將進入老年代,如果年齡不夠但s區裝不下時,也會將對象放入老年代。
  3. 老年代滿了將會進行FGC,FGC不應該頻繁進行
  4. 除Epsilon 、ZGC 、Shenandoah之外的GC都是使用邏輯分代模型,G1是邏輯分代,物理不分代,除此之外不僅邏輯分代,而且物理分代。
  5. 分配擔保:YGC期間,survivor區的空間不夠了,空間擔保直接進入老年代
    在這裏插入圖片描述

常見的垃圾回收器

在這裏插入圖片描述

Serial系列

隨JDK誕生的垃圾回收器是Serial,Serial是一種單線程串行的年輕代垃圾回收器,垃圾回收時會Stop The World(所有工作線程停止),暫停所有工作線程,進行垃圾回收。而Serial Old是老年代的Serial。
在這裏插入圖片描述

Parallel系列

爲了提高效率,減少STW時間,出現了Parallel Scavenge,簡稱PS,該垃圾回收器在垃圾回收時啓動多個線程並行的進行垃圾回收,減少了STW時間,Parallel Old,簡稱PO則是老年代的Parallel Scavenge。
在這裏插入圖片描述

CMS

隨着內存空間的進一步擴大,PS\PO的STW時間越來越長,因此出現了CMS這種併發垃圾回收器,而ParNew是爲了配合CMS而誕生的年親代垃圾回收器,CMS標記時使用三色標記法,三色標記將對象分爲三種顏色,不同顏色代表對象的不同狀態(如下圖1),使用該算法會出現漏標的問題(當黑色對象指向一個白色對象,而原來指向白色對象的灰色對象丟棄了 指向該白色對象的指針時,會使得該白色對象漏標,解決辦法有兩種,如圖3,CMS使用第一種解決辦法)。

  • CMS (ConcurrentMarkSweep)老年代垃圾回收器 使用標記清除算法的併發的垃圾回收器, 垃圾回收和應用程序同時運行,降低STW的時間, CMS問題比較多,所以現在沒有一個版本默認是CMS,只能手工指定。 CMS既然是MarkSweep,就一定會有碎片化的問題,碎片到達一定程度,CMS的老年代分配對象分配不下的時候,使用SerialOld 進行老年代回收,所以應儘量避免fullGC。

  • CMS的幾個過程 初始化標記(STW)、併發標記、重新標記(STW)、清理
    在這裏插入圖片描述
    圖1:
    在這裏插入圖片描述
    圖2:

    圖3
    在這裏插入圖片描述

G1

G1(Garbage First),該垃圾回收器是在CMS的基礎上進一步的改進,它是用到了三色標記+SATB這第二種解決漏標問題的方案,它的特點包含,第一,和CMS一樣併發收集,第二,它可以預測GC的暫停時間,第三,該垃圾回收器相比於CMS吞吐量層面有所下降,但相應時間上佔據有利地位。

G1採用了邏輯分代,物理不分代的全新策略,它將內存劃分爲一個個的region,將內存回收放到一個個的小region上,而不是整個年輕代或老年代。
在這裏插入圖片描述
G1的有3種類型的回收,不同的條件會觸發不同的回收,YGC和MixedGC也可能混着來。第一,年輕代的回收YGC,普通的GC過程;第二,MixedGC(類似CMS的過程)當對象分配佔據整個堆大小的某個值時(默認45%,可設定),可以觸發MixedGC(年輕代,老年代都會回收);第三,fullGC,當對象不能找到一個region分配時,出發fullGC,該過程是單線程的GC過程,需要避免。

回收採用複製算法;回收不是所有的region都回收,而是選擇垃圾最多的region進行垃圾回收,這也是Garbage first的由來
在這裏插入圖片描述
G1的年輕代與老年代沒有固定的大小比例(年輕代佔據整個堆的5%-60%),處於動態的變化中,這也是G1預測暫停時間的保證。

G1中的兩個概念解讀
- Cset(collocation set)G1在進行垃圾回收時,不是將整個內存中的年輕代或老年代都回收,而是選擇垃圾最多的一些region進行,而Cset即爲這些region的集合。
- Rset(Remember set)G1的每個region裏會有一部分內存用來記錄當前region中的對象是否有其他region中的對象的引用指向(是否有其他region中的對象指向當前region中的對象)。

ZGC

是對G1的進一步改進,算法:ColoredPointers + LoadBarrier

Shenandoah

算法:ColoredPointers + WriteBarrier

Eplison

Eplison只有在debug的時候會用到。

垃圾回收器總結

  1. 垃圾收集器跟內存大小的關係,可以說垃圾回收器的發展正是由於內存的擴大而推動。
    Serial 幾十兆
    PS 上百兆 - 幾個G
    CMS - 20G
    G1 - 上百G
    ZGC - 4T - 16T(JDK13)

  2. 垃圾回收器的發展過程:
    隨JDK誕生的Serial->爲提升效率,出現PS\PO的多線程並行回收器-> 內存進一步加大,爲了減少STW時間,出現CMS\PN併發的垃圾回收器-> 內存進一步擴大出現G1、ZGC

  3. 1.8默認的垃圾回收:PS + ParallelOld

  4. 所有的垃圾回收器都不可避免的有STW。

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