GC是什么時候執行的, 如何判斷對象是否可以被回收,


GC是什么時候執行的

 

垃圾回收是一種回收無用內存空間並使其對未來實例可用的過程。

Eden 區:當一個實例被創建了,首先會被存儲在堆內存年輕代的 Eden 區中。

Survivor 區(S0 和 S1):作為年輕代 GC(Minor GC)周期的一部分,存活的對象(仍然被引用的)從 Eden 區被移動到 Survivor 區的 S0 中。類似的,垃圾回收器會掃描 S0 然后將存活的實例移動到 S1 中。

(譯注:此處不應該是Eden和S0中存活的都移到S1么,為什么會先移到S0再從S0移到S1?)

死亡的實例(不再被引用)被標記為垃圾回收。根據垃圾回收器選擇的不同,要么被標記的實例都會不停地從內存中移除,要么回收過程會在一個單獨的進程中完成。

老年代: 老年代(Old or tenured generation)是堆內存中的第二塊邏輯區。當垃圾回收器執行 Minor GC 周期時,在 S1 Survivor 區中的存活實例將會被晉升到老年代,而未被引用的對象被標記為回收。

老年代 GC(Major GC):相對於 Java 垃圾回收過程,老年代是實例生命周期的最后階段。Major GC 掃描老年代的垃圾回收過程。如果實例不再被引用,那么它們會被標記為回收,否則它們會繼續留在老年代中。

內存碎片:一旦實例從堆內存中被刪除,其位置就會變空並且可用於未來實例的分配。這些空出的空間將會使整個內存區域碎片化。為了實例的快速分配,需要進行碎片整理。基於垃圾回收器的不同選擇,回收的內存區域要么被不停地被整理,要么在一個單獨的GC進程中完成。

垃圾回收中實例的終結

在釋放一個實例和回收內存空間之前,Java 垃圾回收器會調用實例各自的 finalize() 方法,從而該實例有機會釋放所持有的資源。雖然可以保證 finalize() 會在回收內存空間之前被調用,但是沒有指定的順序和時間。多個實例間的順序是無法被預知,甚至可能會並行發生。程序不應該預先調整實例之間的順序並使用 finalize() 方法回收資源。

  • 任何在 finalize過程中未被捕獲的異常會自動被忽略,然后該實例的 finalize 過程被取消。
  • JVM 規范中並沒有討論關於弱引用的垃圾回收機制,也沒有很明確的要求。具體的實現都由實現方決定。
  • 垃圾回收是由一個守護線程完成的。

 

如何判斷對象是否可以被回收

jvm 虛擬機會通過 可達性分析法,從gc root開始向下搜索,被搜索走過的路徑稱為引用鏈,當一個對象沒有被GC roots引用鏈連接時,則證明此對象不可用,那么虛擬機就判斷這個對象是可以被回收的。

 

GC roots 的對象有哪些

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

2 方法區中類靜態屬性引用的對象

3 方法區中常量引用的對象

4 本地方法棧中Native方法引用的對象

 

可達性算法中的不可達對象並不是立即死亡的,對象擁有一次自我拯救的機會。對象被系統宣告死亡至少要經歷兩次標記過程,第一次是經過可達性分析發現沒有與GC roots 相連接的引用鏈,第二次是由虛擬機自動建立的Finallizer隊列中判斷是否需要執行finalize()方法。

當對象變成(GC roots)不可達是,GC會判斷該對象是否覆蓋了 finalize方法,若未覆蓋,則直接將其回收,若對象為執行finalize方法,將其放入F-Queue隊列,由一低優先級線程執行該隊列中對象的finalize方法。執行finalize方法完畢后,GC會再次判斷該對象是否可達,若不可達,則進行回收,否則對象”復活“。

每個對象只能觸發異常finalize()方法

由於finalize()方法運行代價高昂,不確定性大,無法保證各個對象的調用順序,不推薦使用。

 


免責聲明!

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



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