? ? 先來(lái)回顧下運(yùn)行時(shí)數(shù)據(jù)區(qū),分為方法區(qū)、堆區(qū)、虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器,其中虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器是線(xiàn)程私有的,隨著線(xiàn)程的創(chuàng)建而生,線(xiàn)程的銷(xiāo)毀而滅,棧中的棧幀隨著方法的進(jìn)入和退出有條不紊執(zhí)行著入棧和出棧的操作,每一個(gè)棧幀中分配的內(nèi)存在類(lèi)結(jié)構(gòu)確定后就已知,因此這幾個(gè)區(qū)域的內(nèi)存分配和回收都是確定的,在方法結(jié)束或線(xiàn)程結(jié)束后就被銷(xiāo)毀了。而堆和方法區(qū)則不一樣,我們只有在程序運(yùn)行期間才能知道哪些對(duì)象會(huì)被創(chuàng)建,這部分內(nèi)存的分配和回收都是動(dòng)態(tài)的,垃圾回收器主要關(guān)注的是這部分內(nèi)存。
對(duì)象死了嗎?
? ? 垃圾回收器回收的死的對(duì)象,那么怎么確定一個(gè)對(duì)象已死呢?
引用計(jì)數(shù)器法
? ? 給對(duì)象添加一個(gè)引用計(jì)數(shù)器,每有一個(gè)地方引用該對(duì)象時(shí)就給引用計(jì)數(shù)器加1,當(dāng)引用計(jì)數(shù)器為0時(shí)該對(duì)象不能再被使用,則可以被垃圾回收器回收,但她很難解決一個(gè)問(wèn)題:對(duì)象之間的相互引用問(wèn)題:
public class test{
public Object o = null;
public static void main(String args[]){
Test t1 = new Test(); ? ?? Test t2 = new Test();
t1.o = t2; ? ?t2.o=t1;
t1=null; ?t2=null;
????}
test1 和test2都已經(jīng)不能被訪(fǎng)問(wèn)了,但他們內(nèi)部相互持有對(duì)象的引用,引用計(jì)數(shù)器為1,引用計(jì)數(shù)器無(wú)法通知垃圾回收器回收這兩個(gè)不再使用的對(duì)象。
}
可達(dá)性分析
? ? 這個(gè)算法的基本思路是通過(guò)一些列的稱(chēng)為"GC Roots" 的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑稱(chēng)為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí)(從GC Roots到這個(gè)對(duì)象不可達(dá)),則證明此對(duì)象不可用??梢员慌卸槭强苫厥諏?duì)象。

上面的這張圖,對(duì)象objectE、objectF、objectG雖然互相有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的,所以它們將會(huì)被判定為是可回收的對(duì)象
在java語(yǔ)言中,可作為GC Roots的對(duì)象有以下幾種:
1.虛擬機(jī)棧(棧幀的局部變量表里)中引用的對(duì)象
2.方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象
3.方法區(qū)中常量引用的對(duì)象
4.本地方法棧中(Native方法)引用的對(duì)象
引用
? ? 在JDK1.2以后加強(qiáng)了引用的概念,將引用分為強(qiáng)引用、弱引用、軟引用、虛引用,依次減弱。
? ? 強(qiáng)引用:就是代碼里Object a = new Object();這樣的引用,這類(lèi)的引用,只要強(qiáng)引用就不會(huì)被回收。
? ? 軟引用:是用來(lái)描述還有用但并非必須的對(duì)象,對(duì)于軟引用關(guān)聯(lián)的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出之前,回收這類(lèi)的對(duì)象,如果還不足則拋OutofMemoryError異常,提供SoftReference類(lèi)來(lái)實(shí)現(xiàn)軟引用。
? ? 弱引用:用來(lái)描述非必須的對(duì)象,被弱引用關(guān)聯(lián)的對(duì)象只能存活到下一次垃圾回收之前,當(dāng)垃圾回收器工作時(shí),無(wú)論當(dāng)前內(nèi)存是否充足,都會(huì)回收該類(lèi)對(duì)象,提供WeakReference類(lèi)來(lái)實(shí)現(xiàn)弱引用。
? ? 虛引用:是最弱的引用,也稱(chēng)為幽靈引用或幻影引用,一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)一個(gè)虛引用來(lái)取得對(duì)象的實(shí)例,為對(duì)象虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被垃圾器回收前得到一個(gè)通知,提供PhantomReference類(lèi)來(lái)實(shí)現(xiàn)虛引用。
對(duì)象是否回收:
? ? 在對(duì)象經(jīng)過(guò)可達(dá)性分析被判斷為不可達(dá)后,也不是一定被回收,要真正宣告一個(gè)對(duì)象死亡有兩次標(biāo)記過(guò)程,在可達(dá)性分析后標(biāo)記為不可達(dá),那么它將會(huì)被進(jìn)行第一次標(biāo)記并進(jìn)行一次篩選,篩選的條件是該對(duì)象是否有必要執(zhí)行finalize(),如果沒(méi)有覆蓋Object的finalize()或已經(jīng)執(zhí)行過(guò)finalize(),則進(jìn)行第二次標(biāo)記并回收。如果對(duì)象有必須要執(zhí)行finalize(),那么這個(gè)對(duì)象將會(huì)加入到F-Queue隊(duì)列中,執(zhí)行她們的finalize(),但不一定會(huì)等到他們執(zhí)行結(jié)束,這是因?yàn)槿绻硞€(gè)對(duì)象的finalize()阻塞了,則可能導(dǎo)致垃圾回收器工作異常,從而系統(tǒng)崩潰,如果在finalize()中將對(duì)象自身的引用賦給某個(gè)對(duì)象的屬性,則可以擺脫這一次的回收,如果沒(méi)有賦值則進(jìn)行第二次標(biāo)記。
注:finalize()只會(huì)被系統(tǒng)調(diào)用一次。最好不要使用她。
回收方法區(qū)
????????很多人認(rèn)為方法區(qū)(或者Hotspot虛擬機(jī)中的永久帶)是不會(huì)被回收的,因?yàn)榛厥辗椒▍^(qū)的性?xún)r(jià)比或者說(shuō)效率比較低,在堆中尤其是新生代,常規(guī)應(yīng)用進(jìn)行一次垃圾收集一般可以達(dá)到70%-95%的空間,而永久帶的垃圾收集效率遠(yuǎn)低于此。
? ? ? ? 永久帶的垃圾收集主要包含兩部分:廢棄常量和無(wú)用的類(lèi)(類(lèi)卸載)。
? ? ? ? 回收廢棄常量與回收java堆中的對(duì)象非常類(lèi)似,以常量池中字面量的回收為例,加入一個(gè)字符串"abc"已經(jīng)進(jìn)入到常量池,但當(dāng)前系統(tǒng)中沒(méi)有任何一個(gè)String對(duì)象是叫做"abc"的,就是沒(méi)有任何引用去指向這個(gè)對(duì)象,如果這時(shí)發(fā)生內(nèi)存回收,而且有必要的話(huà),這個(gè)"abc"常量將被系統(tǒng)回收,常量池中其他類(lèi)(接口)、方法、字段的符號(hào)引用也與此類(lèi)似。
? ? ? ? 無(wú)用類(lèi)回收則對(duì)象苛刻許多,類(lèi)需要同時(shí)滿(mǎn)足下面三個(gè)條件才算是"無(wú)用的類(lèi)":
1.該類(lèi)所有的實(shí)例都已經(jīng)被回收(堆中沒(méi)有該類(lèi)的實(shí)例)
2.加載該類(lèi)的ClassLoader已經(jīng)被回收
3.該類(lèi)對(duì)應(yīng)的Class對(duì)象沒(méi)有在任何地方被引用,無(wú)法在任何地方通過(guò)反射訪(fǎng)問(wèn)該類(lèi)的方法。
????????虛擬機(jī)可以對(duì)滿(mǎn)足上述三個(gè)條件的類(lèi)進(jìn)行回收,并不是一定會(huì)被回收,是否對(duì)類(lèi)進(jìn)行回收需要設(shè)置虛擬機(jī)的參數(shù)(真想弄去查參數(shù)吧)。需要回收的場(chǎng)景:在大量使用反射、動(dòng)態(tài)代理、CGlib等ByteCode框架、動(dòng)態(tài)生成JSP以及OSGI這類(lèi)頻繁自定義ClassLoader的場(chǎng)景都需要虛擬機(jī)具備類(lèi)卸載的功能,以保證永久代不會(huì)溢出。
下一節(jié)將介紹垃圾回收算法。
當(dāng)它本可進(jìn)取時(shí),卻故作謙卑;
當(dāng)它在空虛時(shí),用愛(ài)欲來(lái)填充;
在困難和容易之間,它選擇了容易;
它犯了錯(cuò),卻借由別人也會(huì)犯錯(cuò)來(lái)寬慰自己;
它自由軟弱,卻把它認(rèn)為是生命的堅(jiān)韌;
當(dāng)它鄙夷一張丑惡的嘴臉時(shí),卻不知那正是自己面具中的一副;
它側(cè)身于生活的污泥中,雖不甘心,卻又畏首畏尾。