前言
- 垃圾收集GC(Garbage Collection)是Java語言的核心技術之一,GC通過確定對象是否被活動對象引用來確定是否收集該對象。GC首先要判斷該對象是否是可以收集。兩種常用的方法是引用計數算法和對象引用遍歷。
- 垃圾回收機制主要作用于java堆(Heap),也就是jvm用于存放對象實例的地方.
引用計數算法
引用計數是垃圾收集器中的早期策略。在這種方法中,堆中每個對象(不是引用)都有一個引用計數。當一個對象被創(chuàng)建時,且將該對象分配給一個變量,該變量計數設置為1。當任何其它變量被賦值為這個對象的引用時,計數加1(a = b,則b引用的對象+1),但當一個對象的某個引用超過了生命周期或者被設置為一個新值時,對象的引用計數減1。任何引用計數為0的對象可以被當作垃圾收集。當一個對象被垃圾收集時,它引用的任何對象計數減1。
- 優(yōu)點:引用計數收集器可以很快的執(zhí)行,交織在程序運行中。對程序不被長時間打斷的實時環(huán)境比較有利。
- 缺點: 無法檢測出循環(huán)引用。如父對象有一個對子對象的引用,子對象反過來引用父對象。這樣,他們的引用計數永遠不可能為0.如:
public class ReferenceCountingGC{
public Object instance = null;
public static void testGC(){
ReferenceCountingGC objA = new ReferenceCountingGC ();
ReferenceCountingGC objB = new ReferenceCountingGC ();
objB.instance = objA;
objA.instance = objB;
objA = null;
objB = null;
System.gc();
}
}
要是虛擬機用了引用計數算法,那么上面的objA和objB會不會回收呢?
可達性分析算法(Rearchability Analysis)
早期的JVM使用引用計數,現在在主流的商用的程序語言中,都是稱通過可達性分析算法來判斷對象是否還存活著。這個算法是通過一系列的“GC roots”的對象作為起點,從這些節(jié)點向下搜索,搜索所經過的路徑稱為引用鏈,當一個對象到GC roots沒有任何引用鏈相連的時候。則此對象是不可用的。不可用的對象則是JVM判定為可回收的對象。
在java中,可作為gc roots的對象包括下面幾種:
- 虛擬機棧中引用的對象
- 方法區(qū)中類靜態(tài)屬性引用的對象
- 方法區(qū)中常量引用的對象
- 本地方法棧中JNI引用的對象
就算是在可達性分析算法是不可達的對象,也不是非死不可,現在它們只是被“懷疑”,要真正宣告一個對象死亡,至少要經過兩個階段:在可達性分析的時候,要是不可達,那么它會被第一次標記并且進行一次篩選,篩選的條件是此對象有沒有必要執(zhí)行finalize()方法,當對象沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機調用過。那么,此對象就沒有必要執(zhí)行finalize()方法。
當一個對象被判定為有必要執(zhí)行finalize()方法的時候,它就會被放到一個F-Queue的隊列中,并且稍后會有一個由虛擬機自動創(chuàng)建的線程來執(zhí)行它,而且在執(zhí)行它的時候,虛擬機不保證會等待它運行結束,這是因為要是finalize()里面有死循環(huán)或者什么的就麻煩了,就會堵塞隊列,有時會導致垃圾回收系統(tǒng)崩潰。稍后GC還會再次對F-Queue進行小規(guī)模地第二次標記,如果這次不幸成功被標記,那么它基本上真的就會被回收了。上面說了,finalize()不保證被完全執(zhí)行,所以我們在開發(fā)中,最好不要用它來關閉資源什么的,因為try finally能更好地完成這項工作,所以建議大家忘記這個方法。
參考資料
- JVM GC垃圾回收機制
- 《深入理解java虛擬機》