垃圾回收主要管理的就是java堆,因爲虛擬機棧,本地方法棧,都是線程私有的線程消亡,內存自動回收,並且對象在創建過程時,在棧中需要分配多少內存,是明確知道大小的。如何判斷java堆中對象已經失去引用,就顯得尤爲重要。
1.引用計數算法
爲對象添加一個計數器,有引用加1,失去引用,就減1.收集的時候收集,計數器爲0的對象。
這種算法,不被java虛擬機作爲主流的算法所使用,是因爲,java中,對象循環引用,將會造成,計數器永遠不爲0。從而降低收集效率。具體如下:
class Test{
public Object init;
}
public static void main(arg 0[]){
Test t1=new Test();
Test t2=new Test();
t1.init=t2;
t2.inti=t1;
t1=null;
t2=null;
System.gc();
}
2.可達性分析算法
通過一系列稱爲“GC Roots”對象作爲起點,從這些節點,向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GCRoots沒有任何引用鏈的時候,證明此對象不可達,也就證明對象沒有引用,則會被回收。
java可以作爲GCroots對象的有:虛擬機棧中本地變量表引用的對象;本地方法棧中native方法引用的對象;方法區中靜態屬性引用的對象;方法區中常量引用的對象;
在內存空間足夠,一些雞肋對象,可以回收,也可以不回收,但是這類對象已經沒有引用。但是還想保留這類對象,所有虛擬機將引用分爲四類。這類雞肋對象,也是一些系統中,放入緩存中的對象。
引用可分爲:強引用,軟引用,弱引用,虛引用四類。
強引用:就是用直接引用的對象,這類對象永遠不會被回收。Object o = new Object();
軟引用:這就是那類還有用,但非必須的對象。在報內存溢出異常之前,gc會第二次回收這類對象,會收完如果內存還不夠,纔會報內存異常。
弱引用:比軟引用還要弱,只能活到下次垃圾收集,無論內存是否夠,都會被垃圾收集器收集。
虛引用:無法通過需引用來獲得對象事例,需引用也不會影響對象的生存週期,設置需引用,就是爲了對象在垃圾回收時,收到一個系統通知。
對象的死亡
可達性算法不可達的對象,在經歷可達性算法分析後,不能達到GCRoots根節點,將被進行一次標記,要真正的回收對象,至少要被標記兩次。如果被第一次標記完成後,會對該對象進行一側篩選,篩選的條件就是,看對象是否有必要執行,finalize()方法。當對象沒覆蓋finalize()方法,或者finalize()方法已經被jvm掉用過,這兩種情況都視爲“沒有必要執行”。如果有必要執行finalize()方法,那麼該對象將被放到F—Queue隊列。jvm將會創建一個低優先級的現場,去執行,觸發對象裏面的finalize()方法。不會等待對象執行完畢,防止由於某個對象的finalize()方法,發生死鎖或者死循環,而導致整個內存回收系統崩潰。
回收方法區
主要回收常量池和無用的類。
回收常量池,常量池中的對象,沒有引用,在內存回收時,則被回收。
無用的類:(1)該類的所有實例均被回收。(2)加載該類的ClassLoader已經被回收。(3)該類對應的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。類的回收,和對象回收不同,無用的類,僅僅是可以回收,而不是理馬上被回收。虛擬機提供了,對應的參數,來設置開啓類回收。在大量使用反射,動態代理,CGLib等ByteCode框架、懂贏生成jsp以及OAGI這類頻繁自定義ClassLoader的場景下,需要虛擬機具備類卸載功能,保證不發生內存溢出。