GC roots

1.虛擬機棧(本地變量表)引用的對象html

2.方法區靜態屬性引用的對象
3.方法區常量引用的對象
4.本地方法棧JNI(通常指naive方法)中引用的對象
 

常說的GC(Garbage Collector) roots,特指的是垃圾收集器(Garbage Collector)的對象,GC會收集那些不是GC roots且沒有被GC roots引用的對象。java

一個對象能夠屬於多個root,GC root有幾下種:算法


  • Class - 由系統類加載器(system class loader)加載的對象,這些類是不可以被回收的,他們能夠以靜態字段的方式保存持有其它對象。咱們須要注意的一點就是,經過用戶自定義的類加載器加載的類,除非相應的java.lang.Class實例以其它的某種(或多種)方式成爲roots,不然它們並非roots,.
  • Thread - 活着的線程
  • Stack Local - Java方法的local變量或參數
  • JNI Local - JNI方法的local變量或參數
  • JNI Global - 全局JNI引用
  • Monitor Used - 用於同步的監控對象
  • Held by JVM - 用於JVM特殊目的由GC保留的對象,但實際上這個與JVM的實現是有關的。可能已知的一些類型是:系統類加載器、一些JVM知道的重要的異常類、一些用於處理異常的預分配對象以及一些自定義的類加載器等。然而,JVM並無爲這些對象提供其它的信息,所以就只有留給分析分員去肯定哪些是屬於"JVM持有"的了。

如下是一張由Java Profiler的標示出哪些是GC roots的示例圖:bootstrap

 

做者:RednaxelaFX
連接:https://www.zhihu.com/question/53613423/answer/135743258
來源:知乎
著做權歸做者全部,轉載請聯繫做者得到受權。數據結構

 

以前看深刻理解JVM這本書,對裏面的GC ROOT的真實含義不是太清楚,網上查了一大堆資料都沒有說的很清楚,下面這是從知乎大神上看到的,這裏面記錄一下,和你們一塊兒學習併發

 

所謂「GC roots」,或者說tracing GC的「根集合」,就是一組必須活躍的引用。
例如說,這些引用可能包括:
  • 全部Java線程當前活躍的棧幀裏指向GC堆裏的對象的引用;換句話說,當前全部正在被調用的方法的引用類型的參數/局部變量/臨時值。
  • VM的一些靜態數據結構裏指向GC堆裏的對象的引用,例如說HotSpot VM裏的Universe裏有不少這樣的引用。
  • JNI handles,包括global handles和local handles
  • (看狀況)全部當前被加載的Java類
  • (看狀況)Java類的引用類型靜態變量
  • (看狀況)Java類的運行時常量池裏的引用類型常量(String或Class類型)
  • (看狀況)String常量池(StringTable)裏的引用
注意,是一組必須活躍的引用,不是對象。

Tracing GC的根本思路就是:給定一個集合的引用做爲根出發,經過引用關係遍歷對象圖,能被遍歷到的(可到達的)對象就被斷定爲存活,其他對象(也就是沒有被遍歷到的)就天然被斷定爲死亡。注意再注意:tracing GC的本質是經過找出全部活對象來把其他空間認定爲「無用」,而不是找出全部死掉的對象並回收它們佔用的空間。
GC roots這組引用是tracing GC的起點。要實現語義正確的tracing GC,就必需要能完整枚舉出全部的GC roots,不然就可能會漏掃描應該存活的對象,致使GC錯誤回收了這些被漏掃的活對象。

這就像任何遞歸定義的關係同樣,若是隻定義了遞推項而不定義初始項的話,關係就沒法成立——無從開始;而若是初始項定義漏了內容的話,遞推出去也會漏內容。

那麼分代式GC對GC roots的定義有什麼影響呢?
答案是:分代式GC是一種部分收集(partial collection)的作法。在執行部分收集時,從GC堆的非收集部分指向收集部分的引用,也必須做爲GC roots的一部分。
具體到分兩代的分代式GC來講,若是第0代叫作young gen,第1代叫作old gen,那麼若是有minor GC / young GC只收集young gen裏的垃圾,則young gen屬於「收集部分」,而old gen屬於「非收集部分」,那麼從old gen指向young gen的引用就必須做爲minor GC / young GC的GC roots的一部分。
繼續具體到HotSpot VM裏的分兩代式GC來講,除了old gen到young gen的引用以外,有些帶有弱引用語義的結構,例如說記錄全部當前被加載的類的SystemDictionary、記錄字符串常量引用的StringTable等,在young GC時必需要做爲strong GC roots,而在收集整堆的full GC時則不會被看做strong GC roots。

換句話說,young GC比full GC的GC roots還要更大一些。若是不能理解這個道理,那整個討論也就無從談起了。
 
複製代碼
Garbage Collection Roots
A garbage collection root is an object that is accessible from outside the heap. The following reasons make an object a GC root:
System Class
Class loaded by bootstrap/system class loader. For example, everything from the rt.jar like java.util.* .
JNI Local
Local variable in native code, such as user defined JNI code or JVM internal code.
JNI Global
Global variable in native code, such as user defined JNI code or JVM internal code.
Thread Block
Object referred to from a currently active thread block.
Thread
A started, but not stopped, thread.
Busy Monitor
Everything that has called wait() or notify() or that is synchronized. For example, by calling synchronized(Object) or by entering a synchronized method. Static method means class, non-static method means object.
Java Local
Local variable. For example, input parameters or locally created objects of methods that are still in the stack of a thread.
Native Stack
In or out parameters in native code, such as user defined JNI code or JVM internal code. This is often the case as many methods have native parts and the objects handled as method parameters become GC roots. For example, parameters used for file/network I/O methods or reflection.
Finalizable
An object which is in a queue awaiting its finalizer to be run.
Unfinalized
An object which has a finalize method, but has not been finalized and is not yet on the finalizer queue.
Unreachable
An object which is unreachable from any other root, but has been marked as a root by MAT to retain objects which otherwise would not be included in the analysis.
Java Stack Frame
A Java stack frame, holding local variables. Only generated when the dump is parsed with the preference set to treat Java stack frames as objects.
Unknown
An object of unknown root type. Some dumps, such as IBM Portable Heap Dump files, do not have root information. For these dumps the MAT parser marks objects which are have no inbound references or are unreachable from any other root as roots of this type. This ensures that MAT retains all the objects in the dump

做者:秦漢郵俠
連接:https://www.jianshu.com/p/f4ff9fcc0759
來源:簡書
簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
複製代碼

 

 

參考:less

https://www.jianshu.com/p/f4ff9fcc0759jvm

 

原文地址:https://www.cnblogs.com/FlyAway2013/p/10240919.html

題主對「GC roots」的概念的理解徹底錯誤
若是題主是把「GC roots」(根引用集合)實質上理解成了「live set」(存活的對象的集合)的概念的話,這就好理解了。不然很難理解題主想說的是什麼意思。ide

=================================================post

題主說:
個人理解是jvm不可能把GC roots找全乎了,把全部的gc root所有找出來也能夠可是效率過低

所謂「GC roots」,或者說tracing GC的「根集合」,就是一組必須活躍的引用
例如說,這些引用可能包括:
  • 全部Java線程當前活躍的棧幀裏指向GC堆裏的對象的引用;換句話說,當前全部正在被調用的方法的引用類型的參數/局部變量/臨時值。
  • VM的一些靜態數據結構裏指向GC堆裏的對象的引用,例如說HotSpot VM裏的Universe裏有不少這樣的引用。
  • JNI handles,包括global handles和local handles
  • (看狀況)全部當前被加載的Java類
  • (看狀況)Java類的引用類型靜態變量
  • (看狀況)Java類的運行時常量池裏的引用類型常量(String或Class類型)
  • (看狀況)String常量池(StringTable)裏的引用

注意,是一組必須活躍的引用,不是對象。

Tracing GC的根本思路就是:給定一個集合的引用做爲根出發,經過引用關係遍歷對象圖,能被遍歷到的(可到達的)對象就被斷定爲存活,其他對象(也就是沒有被遍歷到的)就天然被斷定爲死亡。注意再注意:tracing GC的本質是經過找出全部活對象來把其他空間認定爲「無用」,而不是找出全部死掉的對象並回收它們佔用的空間。
GC roots這組引用是tracing GC的起點。要實現語義正確的tracing GC,就必需要能完整枚舉出全部的GC roots,不然就可能會漏掃描應該存活的對象,致使GC錯誤回收了這些被漏掃的活對象。

這就像任何遞歸定義的關係同樣,若是隻定義了遞推項而不定義初始項的話,關係就沒法成立——無從開始;而若是初始項定義漏了內容的話,遞推出去也會漏內容。

那麼分代式GC對GC roots的定義有什麼影響呢?
答案是:分代式GC是一種部分收集(partial collection)的作法。在執行部分收集時,從GC堆的非收集部分指向收集部分的引用,也必須做爲GC roots的一部分。
具體到分兩代的分代式GC來講,若是第0代叫作young gen,第1代叫作old gen,那麼若是有minor GC / young GC只收集young gen裏的垃圾,則young gen屬於「收集部分」,而old gen屬於「非收集部分」,那麼從old gen指向young gen的引用就必須做爲minor GC / young GC的GC roots的一部分。
繼續具體到HotSpot VM裏的分兩代式GC來講,除了old gen到young gen的引用以外,有些帶有弱引用語義的結構,例如說記錄全部當前被加載的類的SystemDictionary、記錄字符串常量引用的StringTable等,在young GC時必需要做爲strong GC roots,而在收集整堆的full GC時則不會被看做strong GC roots。

換句話說,young GC比full GC的GC roots還要更大一些。若是不能理解這個道理,那整個討論也就無從談起了。

順帶放幾個傳送門:

=================================================

那麼分代有什麼好處?

對傳統的、基本的GC實現來講,因爲它們在GC的整個工做過程當中都要「stop-the-world」,若是能想辦法縮短GC一次工做的時間長度就是件重要的事情。若是說收集整個GC堆耗時太長,那不如只收集其中的一部分?
因而就有好幾種不一樣的劃分(partition)GC堆的方式來實現部分收集,而分代式GC就是這其中的一個思路。

這個思路所基於的基本假設你們都很熟悉了:weak generational hypothesis——大部分對象的生命期很短(die young),而沒有die young的對象則極可能會存活很長時間(live long)。

這是對過往的不少應用行爲分析以後得出的一個假設。基於這個假設,若是讓新建立的對象都在young gen裏建立,而後頻繁收集young gen,則大部分垃圾都能在young GC中被收集掉。因爲young gen的大小配置一般只佔整個GC堆的較小部分,並且較高的對象死亡率(或者說較低的對象存活率)讓它很是適合使用copying算法來收集,這樣就不但能下降單次GC的時間長度,還能夠提升GC的工做效率。

放幾個傳送門:

可是!有些比較先進的GC算法是增量式(incremental)的,或者部分併發(mostly-concurrent),或者乾脆徹底併發(fully-concurrent)的。
例如鄙司Azul Systems的Zing JVM裏的C4 GC,就是一個徹底併發的GC算法。它不存在「GC整個工做流程中都要把應用stop-the-world」的問題——從算法的設計上就不存在。
然而C4卻也是一個分兩代的分代式GC。爲何呢?
C4 GC的前身是Azul System的上一代JVM裏的「Pauseless GC」算法,而Pauseless是一個徹底併發可是不分代的GC。

Oracle的HotSpot VM裏的G1 GC,在最初設計的時候是不分代的部分併發+增量式GC,然後來在實際投入生產的時候使用的卻也是分兩代的分代式GC設計。

如今Red Hat正在開發中的Shenandoah GC是一個併發GC,它目前的設計仍是不分代的,但根據過往經驗看,它後期漸漸發展爲分代式的可能性極其高——若是這個項目能活足夠久的話。

對於這些GC來講,解決stop-the-world時間太長的問題並非選擇分代的主要緣由。就Azul的Pauless到C4的發展歷程來看,選擇實現分代的最大好處是,GC可以應付的應用內存分配速率(allocation rate)能夠獲得巨大的提高。併發GC根本上要跟應用玩追趕遊戲:應用一邊在分配,GC一邊在收集,若是GC收集的速度能跟得上應用分配的速度,那就一切都很完美;一旦GC開始跟不上了,垃圾就會漸漸堆積起來,最終到可用空間完全耗盡的時候,應用的分配請求就只能暫時等一等了,等GC追遇上來。因此,對於一個併發GC來講,可以儘快回收出越多空間,就可以應付越高的應用內存分配速率,從而更好地保持GC以完美的併發模式工做。雖然並非全部應用中的對象生命週期都完美吻合weak generational hypothesis的假設,但這個假設在很大範圍內仍是適用的,於是也能夠幫助併發GC改善性能。

就先寫這麼多…
相關文章
相關標籤/搜索