一文讀懂JVM垃圾回收器ZGC的設計及算法


從JDK11開始,java支持一種新的垃圾回收器-ZGC,號稱STW在10ms之內,它到底有何神奇之處,今天帶你來揭曉。

ZGC不同於以往的垃圾回收器,只能在64位的機器上使用ZGC,並且壓縮指針會失效,這是由於ZGC使用了一種叫做着色指針的技術。並且ZGC能支持4TB(JDK13開始支持至16TB)。而且ZGC首次完全廢除老年代新生代的概念。

ZGC的核心在於着色指針,但是其高效的秘訣絕不是簡單的着色指針,主要秘訣如下:

1.ZGC進行了JIT編譯器優化,能產生更少的垃圾

2.應用程序線程會對ZGC的處理過程提供一定的幫助(下文會提及)

3.使用了讀屏障

4.支持NUMA(非一致性內存訪問)

內存情況:ZGC前一款垃圾處理器叫G1,首次使用了region,並且把內存分成多個Eden兩個survivor多個Old(每個內存塊是一個region)。ZGC在這個的基礎上更近一步,把內存分為多個region,但是不會限制這個region是Eden還是Old。

着色指針:ZGC的指針都是64位的,其中高18位未使用,中間4位就是着色指針,后面的44位是真實內存地址

 

 

 

 

 

 

讀屏障:渡屏障是在JIT中增強的一小段代碼,會在使用指針獲取對象地址的時候先根據着色指針判斷這個時候獲取是否安全,如果不安全,會等上一會再返回新的對象地址(獲取新的對象地址的方式下面會說到),讀屏障只會在讀取不安全的指針地址時使用,已經讀取到的變量和非指針(基本數據類型)不會使用到讀屏障。

ZGC的執行流程

1.開始標記(STW),找出根節點

2.並行標記,找出垃圾

3.處理邊緣情況(STW)

4.重定位

5.重映射(這一步不算是單獨的一步,一部分重映射會在下一次GC開始的時候和第一步一起執行,另一部分就是應用線程協助完成的)

 

流程詳解:

1.第一次ZGC的時候,ZGC會STW,根據線程棧和常量池查找到所有的根節點

2.恢復應用線程運行,把根節點分配給GC線程,每個線程只標記自己負責的根線程

3.並發的去尋找可達對象,如果對象的某個屬性是引用類型並且指針顯示它還沒有開始標記,會把指向該引用類型的指針置為開始標記

4.標記該對象完成后會把指針置為已標記完成的狀態

5.當所有的對象都標記完成后,開始進行重定位,將對象A移到新的region中,並且把舊的地址和新的地址做一個映射(Forwarding Tables,A'->A ),注意:此時指向該對象的指針仍然是開始重定位狀態,如果此時應用程序訪問原本指向A的指針,會根據映射修改指針的地址為新的地址,並且修改指針狀態為重定位完成,這里就體現了應用程序幫助ZGC完成GC過程的一方面。

6.重定位完成后整個GC過程基本完結。

7.第二次和以后的GC,在查到到根節點根據指針獲取對象時,如果指針的狀態是開始重定位狀態,會根據Forwarding Tabels映射修改指針。

整個過程如下,里面可能有一些不太好理解的點,簡單解答下:

1.對於Java和C不太了解的人可能不知道指針的概念,其實java訪問一個引用對象都是獲取到他的指針,需要訪問該對象時,根據指針的地址去找到相應的對象,所以執行Person p = A.person的時候,p其實獲取的是A.person這個指針,不會說出現A中的person指針被標記為已開始定位,還可以根據p訪問person的情況,此時會發生讀屏障。也不會發生指針狀態為重定位完成,根據p訪問到的是已釋放內存的情況。

2.已釋放的內存如果被重新分配,那么必然是一個新的指針,這個指針的狀態也是初始化的狀態,不會發生根據Forwarding Tables重新定位到其他地址的情況。

整個ZGC的處理流程是我根據openjdk提供的文檔分析得到的,如果有錯,歡迎大家指出!最后附件附上原始文檔,有興趣的小伙伴可以看看。

 https://files.cnblogs.com/files/fiftyonesteps/ZGC%E6%96%87%E6%A1%A3.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM