1. 物件在什麼時候變為垃圾
判斷標準:沒有被其他物件引用
複製程式碼
1.1 引用計數法
- 優點:執行效率高,程式執行受影響小
- 缺點:迴圈引用
1.2 可達性分析演算法
通過判斷物件的引用鏈是否可達來決定物件是否可被回收
複製程式碼
結構圖
可以作為 GC Root 的物件
- 虛擬機器棧中引用的物件(棧幀中的本地變數表)
- 方法區中的常量引用物件
- 方法區中的類靜態屬性引用的物件
- 本地方法棧中 JNI (Native 方法)的引用物件
- 活躍執行緒的引用物件
2. GC 演算法
2.1 標記-清除演算法 (Mark and Sweep)
- 標記:從 GC Root (可達性分析演算法) 進行掃描,對存活的物件進行標記
- 清除:對堆記憶體進行從頭到尾的遍歷,對標記物件進行清理
2.2 複製演算法 (Copying)
該演算法把記憶體分為兩個區域:物件面和空閒面
- 物件在物件面上建立
- 存活的物件將會從物件面中複製到空閒面
- 最後將物件面的所有物件的記憶體釋放 ps:該演算法適用於物件存活率低的場景 (一般用於回收年輕代)
- 優點
- 解決了碎片化問題
- 順序分配記憶體,簡單高效
- 適用與物件存活率低的場景
- 缺點
- 需要兩倍的記憶體空間
- 當物件存活率高的時候,需要複製的物件較多
2.3 標記-整理演算法 (Compacting)
- 標記:與標記清除相同
- 整理:移動所有存活物件,且按照記憶體地址次序依次排列,然後將末端地址以後的記憶體全部回收
- 優點
- 避免了記憶體的不連續行
- 不用設定兩塊互換記憶體
- 適用於存活率高的場景
2.4 分代收集演算法
按照物件的生命週期劃分出不同的區域以採用不同的垃圾回收演算法
目的:提高 JVM 垃圾回收的效率
版本差異
JDK 6 與 JDK 7
JDK 8 及以後2.4.1 Young Generation
目的:儘可能塊的收集掉那些生命週期短的物件
- Eden 區
- 兩個 Survivor 區
當 Eden 空間不足時,會觸發 Minor GC
2.4.2 Old Generation
目的:存放生命週期較長的物件
Full GC
觸發 Full GC 的條件
- 老年代空間不足
- JDK 7 及之前的版本,永久代空間不足
- CMS GC 時,出現 promotion failed 或者 concurrent mode failure
- Minor GC 晉升到老年代的平均大小大於老年代的剩餘空間
- 呼叫 System.gc() (還是由虛擬機器決定是否 GC)
3. GC 相關面試題
3.1 Object 的 finalize() 方法是否與 C++ 中的解構函式類似
- C++ 中的解構函式的呼叫時機是確定的,而 Java 中的是不確定的
- Java 中將未被引用的物件放在 F-Queue 佇列
- Java 中的 finalize 方法執行隨時可能會被終止
- 物件最後一次"重生"機會
3.2 Java 中強引用、軟引用、弱引用和虛引用有什麼用
3.2.1 強引用 (Strong Reference)
- 最普遍的引用:Object obj = new Object();
強引用在 GC 中的特性
- 在 GC 中,GC 寧可丟擲 OutOfMemoryError 終止程式,也不會回收具有強引用的物件
- 如果需要使用 GC 來回收強引用,將物件置為 null 來弱化引用,從而被 GC 回收
3.2.2 軟引用 (Soft Reference)
- 表示一個物件處於有用但非必須的狀態
- 只有在記憶體空間不足時 GC 才會回收該物件使用的記憶體空間
- 可以用來實現記憶體敏感的快取記憶體
// 軟引用的建立方法
SoftReference<String> stringSoftReference = new SoftReference<String>("abc");
複製程式碼
3.2.3 弱引用 (Weak reference)
- 非必須的物件,比軟引用更弱一些
- GC 的時候會被回收,但是被回收的概率也並不大,畢竟 GC 執行緒的優先順序很低
- 適用於引用偶爾被使用且不影響垃圾收集的物件
// 弱引用的建立方法
WeakReference<String> stringWeakReference = new WeakReference<String>("abc");
複製程式碼
3.2.4 虛引用 (Phantom Reference)
- 不會決定記憶體的生命週期
- 任何時候都可能被 GC 回收
- 主要用來跟蹤物件被垃圾收集器回收的活動,起哨兵的作用
- 虛引用必須和引用佇列 ReferenceQueue 聯合使用
// 虛引用的用法
ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
PhantomReference phantomReference = new PhantomReference("abc", referenceQueue);
複製程式碼
3.2.5 層次結構
3.2.6 引用佇列 (Reference Queue)
- 雖然名字中有佇列,但無實際儲存結構,儲存邏輯依賴於內部節點之間的關係來表達
- 儲存關聯且被 GC 的軟引用,弱引用和虛引用
- 虛、