1. 程式人生 > 其它 >深入理解JVM - 垃圾收集

深入理解JVM - 垃圾收集

1. 概述

垃圾收集器 Garbage Collection。
垃圾收集器需要完成的三件事

  • 哪些記憶體需要回收
  • 什麼時候回收
  • 如何回收

只有Java堆和方法區需要考慮記憶體回收,程式計數器、虛擬機器棧、本地方法棧的記憶體分配和回收都具有確定性。

2. 如何判斷物件已死

1. 引用計數法 Reference Counting

在物件中新增一個引用計數器,每當被其他物件引用,計數器+1,引用失效則計數器-1,當計數器值為0時表名該物件不可能再被使用。
原理簡單、判定效率高,難以解決迴圈引用問題。

2. 可達性分析演算法 Reachability Analysis

通過一系列稱之為 GC Roots

的根物件作為起始集,從這些根物件開始,根據引用鏈關係向下搜尋,搜尋過程走過的路徑稱之為引用鏈 Reference Chain,如果某個物件到GC Roots間沒有引用鏈相連,也即從GC Roots到這個物件不可達,則證明該物件不可再被使用。

GC Roots

  1. 虛擬機器棧(棧幀中的區域性變量表)中引用的物件,如引數、區域性變數、臨時變數等。
  2. 本地方法棧中Native方法引用的物件
  3. 方法區中類靜態屬性引用的物件,如Java類的引用型靜態欄位
  4. 方法區中常量引用的物件,如字串常量池中的引用
  5. VM內部引用,如基本資料型別對應的Class物件,常駐異常物件(NPE、OOM),系統類載入器等
  6. 同步鎖/監視器鎖 synchronized 所持有的物件
  7. 反應 JVM 內部情況 JMXBean、JVMTI 中註冊的回撥、原生代碼快取等。

以上是固定 GC Roots,根據使用者選擇的垃圾收集器及當前回收的記憶體區域不同,還可以有其他臨時性物件加入。如分代收集和區域性回收(Partial GC),針對區域性劇區域的回收,還需要考慮該區域內物件被其他區域物件引用。當然為了避免 GC Roots 的膨脹,都進行了各種優化處理。

3. 各種引用

強軟弱虛四種引用。
強引用 Stringly Reference:最傳統的引用,只要還可達,就不會被回收。
軟引用 Soft Reference:OOM前對這些引用進行回收,若記憶體還不足才會OOM。SoftReference 類
弱引用 Weak Reference

:只能生存到下一次 GC。WeakReference 類。
虛引用 Phantom Reference:虛引用的存在不影響物件本身的生存時間,只是在物件被回收時得到通知。PhantomReference 類。

4. 標記過程

要宣告一個物件 不可達,至少需要經歷兩次標記。
第一次判斷不可達,判斷 finalize 方法是否已重寫或是否已被 VM 呼叫過。若沒有,則放入 F-Queue 佇列,由 VM 自動建立的,低優先順序的 Finalizer 執行緒執行 finalize 方法。
第二次對F-Queue物件判斷是否可達,若不可達則此物件宣告死亡。

finalize 釋放資源的問題:執行時間不確定,若某物件 fianlize 執行緩慢甚至死迴圈,可能導致記憶體回收子系統的崩潰。

當物件不可達時,可在 finalize 中拯救自己一次。

5. 方法區回收

主要兩部分內容:廢棄的常量和不再使用的記憶體。
類不再使用

  • 例項全部已被回收
  • 載入該類的類載入器已被回收
  • 該類的 Class 物件沒有被引用
    -Xnoclassgc、-verbose:class、-XX:+TraceClassLoading、-XX:+TraceClassUnLoading