如何判斷物件為垃圾物件
引用計數法
給物件新增一個引用計數器,每當有個物件引用它時,計數器加1;引用失效時計數器減1;為0時物件不可能被再引用。
沒有使用的原因:很難解決物件之間相互迴圈引用的問題
可達性分析演算法
看作為GC Roots的物件作為起始點,和它連通的是可用的,反之不可用。
如下情況的物件可以作為GC Roots:
- 虛擬機器棧(棧楨中的本地變數表)、本地方法棧中JNI(Native方法)中的引用的物件
- 方法區中的類靜態屬性引用的物件
- 方法區中的常量引用的物件
當物件不可達時,可以執行fianlize()
,但該方法自會被自動呼叫一次,有點像c++的解構函式,書上說最好別用。
引用的分類
- 強引用:
Objece obj = new Object()
,永遠不會被垃圾蒐集回收 - 軟引用:
SoftReference
類實現,可以存活第一次回收,但第二次就GG - 弱引用:
WeakReference
類實現,第一次就GG - 虛引用:
PhantomReference
類實現,不能通過它取得例項,唯一作用就是當該物件被回收時會收到一個系統通知。
如何回收
垃圾收集演算法
- 標記-清除演算法:(老年代)先標記,再清除。缺點:效率低,記憶體碎片化
- 複製演算法:(新生代)HotSpot虛擬機器把記憶體分為Eden和2塊Survivor區,把在Eden和Survivor中 存活的物件 複製到空閒的一塊Survivor中。不夠時可以向老年代擔保。
- 標記-整理演算法:(老年代)標記 -> 移動到一起 -> 清理
- 分代收集演算法:把記憶體分為新生代和老年代。根據年代選則合適的演算法。
垃圾收集器
新生代 | 老年代 | 特殊 |
---|---|---|
Serial(單執行緒) | Serial Old(單執行緒,CMS備胎) | G1(Region優先順序回收) |
ParNew(多執行緒) | CMS(併發) | |
Parallel Scavenge(關注吞吐量) |
- 並行(Parallel):多條垃圾收集執行緒並行工作,但此時使用者執行緒仍處於等待狀態。
- 併發(Concurrent):使用者執行緒與垃圾收集執行緒同時執行。
如何分配
以HosSpot收集器的分配和回收策略為例
- 優先分配在Eden
- 大物件直接進入老年代
- 長期存活的物件進入老年代
- 動態物件年齡判定
- 空間分配擔保