我們都知道垃圾回收是指回收那些不再使用的對(duì)象所占的內(nèi)存區(qū)域锁施。生動(dòng)的說挑胸,在 Java 的世界里,無用的人就要拉出去槍斃了夷狰,并且把其所占的地盤清理岭皂,以便讓“別人“來使用。
如何判斷對(duì)象“無用”孵淘?
關(guān)于判斷對(duì)象是否無用的算法蒲障,在JVM的發(fā)展過程中出現(xiàn)過兩種算法:一種是引用計(jì)數(shù)和根集算法。
引用計(jì)數(shù)算法
例如下圖中的object1的引用計(jì)數(shù)是2瘫证,GC的時(shí)候不回收揉阎,object6、object7引用計(jì)數(shù)為0背捌,GC的時(shí)候要被回收毙籽。引用計(jì)數(shù)有個(gè)缺點(diǎn):當(dāng)引用產(chǎn)生閉環(huán)的時(shí)候即便是對(duì)象實(shí)際上已經(jīng)“無用”也無法回收了,例如下圖中的 毡庆,object4坑赡、object5、object8直接引用關(guān)系么抗。
根集算法
引用計(jì)數(shù)算法簡高效毅否,早期的 Java 虛擬機(jī)中使用這個(gè)方式,但是正如上面提到的不能解決“引用閉環(huán)”的問題蝇刀,后來的 Java 虛擬機(jī)中普普采用根集算法螟加。從 GCRoot(比如一個(gè)靜態(tài)變量) 開始遍歷引用關(guān)系,能遍歷到的吞琐,叫做引用可達(dá)捆探,遍歷不到的叫做不可達(dá)。不可達(dá)的對(duì)象就被判“死刑了”站粟,GC的時(shí)候?qū)⒈粯寯赖簟?/p>
對(duì)象回收之后的內(nèi)存如何處置黍图?
人死了、遺產(chǎn)處理不好會(huì)產(chǎn)生很多糾紛奴烙,所以有法律制度助被。在 JVM 的世界里對(duì)象死了剖张,剩下的“遺產(chǎn)”無非就是它占據(jù)的那片內(nèi)存空間。對(duì)象死后生下的那部分內(nèi)存空間進(jìn)行一下規(guī)劃的恰起,具體算法有三種修械。
標(biāo)記-清除
標(biāo)記就是把那些“無用的對(duì)象”標(biāo)記一下,被標(biāo)記的對(duì)象等于被判了死刑检盼,也就是就可以回收了,清除就是變那些被標(biāo)記了的對(duì)象清楚掉翘单。
我們發(fā)現(xiàn)吨枉,清除之后的狀態(tài),其中的可用內(nèi)存并不是連續(xù)的哄芜,也就是說內(nèi)存存在碎片貌亭,如果創(chuàng)建一個(gè)大對(duì)象,無法分配到足夠大的連續(xù)內(nèi)存空間认臊,使得GC不得不做一次重新整理圃庭。由于可用對(duì)象和無用對(duì)象直接的內(nèi)存不是連續(xù)的,所以標(biāo)記的過程是要遍歷識(shí)別內(nèi)存區(qū)域的失晴,清除的過程也是要遍歷識(shí)別的剧腻,整個(gè)過程效率比較低。
標(biāo)記-復(fù)制
標(biāo)記的過程不變涂屁。把內(nèi)存劃分為兩部分书在,一部分叫做預(yù)留區(qū)域(下圖虛線框中),不分配對(duì)象拆又。在GC的時(shí)候把那些正在使用的對(duì)象復(fù)制到預(yù)留區(qū)域儒旬,然后再把非預(yù)留區(qū)域以外的內(nèi)存全部清除。
解決了效率和內(nèi)存碎片的問題帖族,但是代價(jià)是昂貴的:犧牲了1/2的內(nèi)存栈源,顯然在很多情況下是無法接受的。
標(biāo)記-整理
標(biāo)記的過程依然不變竖般,標(biāo)記之后處于內(nèi)存末端區(qū)域的正在使用的對(duì)象向前移動(dòng)占據(jù)覆蓋那些被標(biāo)記了的區(qū)域(有一種碾壓的感覺)甚垦,把正在使用的對(duì)象趕到一起,再把剩余的標(biāo)記對(duì)象全部清除捻激。
分代混合算法
在現(xiàn)代虛擬機(jī)(通常就是 HotSpot(TM))制轰,使用的分代算法來處理內(nèi)存,并沒有什么新意胞谭,只是針對(duì)對(duì)象的生命周期范圍來劃分區(qū)域垃杖,不同的區(qū)域使用不同的算法。一般分為新生代和老生代丈屹,新生代由于生命不長调俘,GC的時(shí)候大部分對(duì)象已經(jīng)死亡伶棒,所以有足夠的空間作為擔(dān)保,可用使用標(biāo)記-復(fù)制算法彩库,對(duì)于老生代老生代使用標(biāo)記-清除或標(biāo)記-整理算法肤无。
Stop the world
想象一下,你不可能在媽媽一邊打掃衛(wèi)生的時(shí)候你一邊扔垃圾吧骇钦,她當(dāng)然希望你乖乖做在沙發(fā)上抬起腳來別動(dòng)宛渐。JVM的世界亦如此,前面我們說道使用引用關(guān)系的根集算法來標(biāo)記對(duì)象是否無用眯搭,二這個(gè)引用關(guān)系只是某一時(shí)刻的“快照”窥翩,使用一個(gè)叫做OopMap的數(shù)據(jù)結(jié)構(gòu)來保存的。引用關(guān)系是會(huì)隨時(shí)間變化的鳞仙,所以在垃圾回收器進(jìn)行垃圾回收時(shí)候就必須的有所停頓寇蚊,sun把這個(gè)現(xiàn)象叫做“Stop the world ”。
所以頻繁的GC會(huì)影響性能棍好,對(duì)象存活時(shí)間過長會(huì)占用內(nèi)存仗岸,在實(shí)際開發(fā)過程中我們?nèi)绾稳テ胶鈨?nèi)存空間和執(zhí)行效率、如何去選擇對(duì)象生命周期是非常重要的借笙。