小師妹學JVM之:Dirty cards和PLAB
阿新 • • 發佈:2020-07-09
[toc]
# 簡介
分代垃圾回收器在進行minor GC的時候會發生什麼操作呢?有沒有什麼提高效率的手段呢?今天我們和小師妹一起來了解一下垃圾回收中的Dirty cards和PLAB
# 分代收集器中的空間劃分
小師妹:F師兄,能再講講分代垃圾收集器中的空間劃分嗎?
分代垃圾回收器中的Eden,Old和Survivor space幾個大家應該都很熟悉的分代技術。
Young Gen被劃分為1個Eden Space和2個Suvivor Space。當物件剛剛被建立的時候,是放在Eden space。
當Eden space滿的時候,就會觸發minor GC。會掃描Eden Space和一個Suvivor Space。如果在垃圾回收的時候發現Eden Space中的物件仍然有效,則會將其複製到另外一個Suvivor Space。
就這樣不斷的掃描,最後經過多次掃描發現仍然有效的物件會被放入Old Gen表示其生命週期比較長,可以減少垃圾回收時間。
![](https://img-blog.csdnimg.cn/20200525214231730.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70)
# Write barrier和Dirty cards
小師妹:F師兄,minor GC的時候,要將物件從Eden複製到Suvivor Space,從Suvivor Space中複製到Old space。GC是怎麼知道哪些物件是要被回收,哪些是不用被回收的呢?
小師妹,GC這裡用到了一項叫做Dirty cards的技術。
一般來說,新的物件是分配在Eden空間的。但是也有些物件是直接分配在Old space。
我們知道,GC的掃描是從一些根物件開始的,這些Root物件包括:正在執行的方法中的本地物件和輸入引數。活動的執行緒,載入類中的static欄位和JNI引用。
而這些根物件,一般都是儲存在old space中的。
通常來說old space的空間都會比較大。每次要要找到Eden和suvivor Space中哪些物件不再被引用,需要掃描整個old space肯定是不可取的。
所以JVM在這裡引入了Write barrier的技術。HotSpot中有兩種Write barrier,一種就是今天我們要講的Dirty cards,另外一種就是snapshot-at-the-beginning (SATB)。 SATB通常用在G1垃圾回收器中,這裡我們先不做深入的討論。
![](https://img-blog.csdnimg.cn/20200607152228268.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70)
我們看下上圖中的Dirty cards的使用。
Dirty cards說起來很簡單,就是每當有程式對引用進行修改的時候,我們都會在一個Dirty cards的空間記錄一下被修改的memory page。
這樣在minor GC的時候,當引用的物件被修改了之後,我們會同步修改對應的Dirty cards。這樣每次掃描old space的時候,只需要選擇那些標記為Dirty cards的物件就可以了,避免了全域性掃描。
# PLAB
小師妹,F師兄,你講的好像很有道理的樣子,上次你講到我們在Eden空間分配物件的,為了提升分配的效率,使用了TLAB的計算。那麼在物件從Eden空間提升到Suvivor Space和old Space的時候有沒有同樣的技術呢?
當然有的,這個技術就叫做PLAB( promotion local allocation buffer)。每一個執行緒在survival space和old space中都一個PLAB。在提升的時候,可以避免多執行緒的競爭,從而提升效率。
我們可以使用-XX:+AlwaysTenure 將物件直接從Eden space提升到old space。
我們可以使用-XX:+PrintOldPLAB來輸出OldPLAB的資訊。
# old space分配物件
小師妹:F師兄,剛剛你講到新分配的物件可以直接在Old space,一般什麼物件可以這樣分配呢?
這個很好理解,如果你分配物件大小超過了Eden space的大小,是不是就只有old space可以分配物件了?
小師妹:對的,但是一般來說也不會使用這麼大的物件吧。
對的,我們可以通過設定-XX:PretenureSizeThreshold=n 來指定物件的大小,如果物件大小大於n,那麼就直接在old space分配。
> 注意,如果這個物件的大小比TLPB要小,那麼會首先在TLPB中分配。所以使用的時候要注意限制TLPB的大小。
# 總結
GC的執行是一個比較複雜的過程,大家可以細細體會。本文如果有什麼謬誤之處,歡迎微信我指正。謝謝大家。
> 本文作者:flydean程式那些事
>
> 本文連結:[http://www.flydean.com/jvm-dirty-card-plab/](http://www.flydean.com/jvm-dirty-card-plab/)
>
> 本文來源:flydean的部落格
>
> 歡迎關注我的公眾號:程式那些事,更多精彩等著您!