G1垃圾回收器--基本知識及原理解析


G1介紹(Garbage first)
G1主要面向的是服務端的垃圾回收器。在G1之前,JVM的主要垃圾回收器采用的是物理分代的思想,將內存區域嚴格的划分成年輕代(young GC)和老年代(major GC),然后針對於年輕代和老年代使用不同的垃圾回收器進行GC操作,直到G1,G1采用的是對整個堆進行回收,並且G1使用的分區region思想將內存划分成了許多的分區。

雖說G1不使用嚴格將內存分為年輕代和老年代,但是在邏輯層面G1還是將分區region貼上了標簽Eden,Survivor,Old,也是一種分代的思想,並且G1針對於特別大的對象(當一個對象會占據一個分區的一般以上空間G1稱為大對象)會將該大對象用一段連續的多個Humongous分區(專門存放大對象)存放。G1的大多數行為都會將Humougous分區判定為老年代看待。
每個region的大小可以通過XX:G1HeapRegionSize設定(取值范圍1~32MB),且為2的N次冪。
G1的停頓時間控制
用戶自定義停頓時間
G1的還有一個特點就是用戶可以通過設置-XX:MaxGCPauseMills來設置用戶允許的停頓時間(默認為200ms),G1會根據這個時間盡可能的回收垃圾,所以這也是G1是比較全能的原因。針對用戶自定義停頓時間我們可以猜想到,G1很可能無法完全回收所有垃圾(因為設定了一個時間),但是G1會盡可能的多收集垃圾。
有點類似於老板給員工制定一個KPI,要求高就多收集點,要求低就少收集點。這也是G1的一個回收特點:並不是回收全部垃圾,而是盡可能在用戶規定得停頓時間內盡可能回收垃圾多的region。
G1如何實現盡可能回收最多垃圾region?
G1之所以能夠建立預測停頓時間的模型,依賴於G1是針對於分區region進行整體回收,即每次回收都是以region為單位。那么G1如何判斷哪些region的回收率高(即垃圾多):G1收集器會跟蹤每個region里面垃圾堆積的價值(即回收該region所獲的空間和所需時間的價值),然后再后台維護一個優先級列表,每次根據該優先級列表進行回收(優先處理優先級高的region),這也是Garbage First的由來。
如果存在跨代引用如何解決?
針對於年輕代的region我們每次都會進行回收,所以不需要考慮年輕代指向老年代。
針對於老年代指向年輕代的引用我們如何選擇(如果不管則使用整個堆的GC root掃描),這里提出的思想是記憶集rset(remember set),
G1是對每個region維護了一個rset,記憶集中維護了指向自己的region的指針,並且標記指針分別在那些卡頁的范圍之內。由於G1使用了很多的region(每個region都有一個rset),所以G1使用了較高的內存,基本占用Java對內存的10%~20%的額外內存來維持收集器的工作。
用戶停頓時間的設置

  • 如果用戶停頓時間過長:那么會導致用戶線程停止很長時間,降低吞吐量。
  • 如果用戶停頓時間過短:那么會導致一次GC回收不了太多的垃圾對象,則會導致頻繁GC,也會降低吞吐量。

G1垃圾收集的工作流程
G1的收集過程主要分為四步:
1.初始標記
僅僅標記GC roots能直接關聯到的對象。該步驟需要STW,但是時間極短。
2.並發標記
從GC roots使用可達性算法,對堆內存中對象進行標記(三色標記法),遞歸掃描整個堆。該步驟耗時過長,是與用戶業務程序並發執行。
3.重新標記
對用戶線程短暫的STW,用於處理並發標記中對象的一些變更情況的最終確定。
4.篩選回收
G1會根據用戶規定的停頓時間,最大的回收region,將需要被回收的region復制到空白region中,再將原region全部回收。該步驟也需要STW,因為涉及到了對象的移動(一個region到另一個region)。

三色標記法

黑色:自身及其子對象已經被標記。
灰色:自身已經被標記,但是子對象沒有完全被標記
白色:自身未被標記,如果標記結束后仍然為白色,則是垃圾對象。


免責聲明!

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



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