Java 对象之死
如何判斷對(duì)象“無(wú)用”?
關(guān)于判斷對(duì)象是否無(wú)用的算法,在JVM的發(fā)展過(guò)程中出現(xiàn)過(guò)兩種算法:一種是引用計(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)“無(wú)用”也無(wú)法回收了,例如下圖中的 ,object4、object5、object8直接引用關(guān)系。
引用計(jì)數(shù)算法
根集算法
引用計(jì)數(shù)算法簡(jiǎn)高效,早期的 Java 虛擬機(jī)中使用這個(gè)方式,但是正如上面提到的不能解決“引用閉環(huán)”的問(wèn)題,后來(lái)的 Java 虛擬機(jī)中普普采用根集算法。從 GCRoot(比如一個(gè)靜態(tài)變量) 開(kāi)始遍歷引用關(guān)系,能遍歷到的,叫做引用可達(dá),遍歷不到的叫做不可達(dá)。不可達(dá)的對(duì)象就被判“死刑了”,GC的時(shí)候?qū)⒈粯寯赖簟?/p>
根集算法
對(duì)象回收之后的內(nèi)存如何處置?
人死了、遺產(chǎn)處理不好會(huì)產(chǎn)生很多糾紛,所以有法律制度。在 JVM 的世界里對(duì)象死了,剩下的“遺產(chǎn)”無(wú)非就是它占據(jù)的那片內(nèi)存空間。對(duì)象死后生下的那部分內(nèi)存空間進(jìn)行一下規(guī)劃的,具體算法有三種。
三種回收算法.png
標(biāo)記-清除
標(biāo)記就是把那些“無(wú)用的對(duì)象”標(biāo)記一下,被標(biāo)記的對(duì)象等于被判了死刑,也就是就可以回收了,清除就是變那些被標(biāo)記了的對(duì)象清楚掉。
GC標(biāo)記之后的狀態(tài)
清除之后的狀態(tài)
我們發(fā)現(xiàn),清除之后的狀態(tài),其中的可用內(nèi)存并不是連續(xù)的,也就是說(shuō)內(nèi)存存在碎片,如果創(chuàng)建一個(gè)大對(duì)象,無(wú)法分配到足夠大的連續(xù)內(nèi)存空間,使得GC不得不做一次重新整理。由于可用對(duì)象和無(wú)用對(duì)象直接的內(nèi)存不是連續(xù)的,所以標(biāo)記的過(guò)程是要遍歷識(shí)別內(nèi)存區(qū)域的,清除的過(guò)程也是要遍歷識(shí)別的,整個(gè)過(guò)程效率比較低。
標(biāo)記-復(fù)制
標(biāo)記的過(guò)程不變。把內(nèi)存劃分為兩部分,一部分叫做預(yù)留區(qū)域(下圖虛線框中),不分配對(duì)象。在GC的時(shí)候把那些正在使用的對(duì)象復(fù)制到預(yù)留區(qū)域,然后再把非預(yù)留區(qū)域以外的內(nèi)存全部清除。
標(biāo)記之后內(nèi)存狀態(tài)
復(fù)制之后內(nèi)存狀態(tài)
清除之后內(nèi)存狀體
解決了效率和內(nèi)存碎片的問(wèn)題,但是代價(jià)是昂貴的:犧牲了1/2的內(nèi)存,顯然在很多情況下是無(wú)法接受的。
標(biāo)記-整理
標(biāo)記的過(guò)程依然不變,標(biāo)記之后處于內(nèi)存末端區(qū)域的正在使用的對(duì)象向前移動(dòng)占據(jù)覆蓋那些被標(biāo)記了的區(qū)域(有一種碾壓的感覺(jué)),把正在使用的對(duì)象趕到一起,再把剩余的標(biāo)記對(duì)象全部清除。
標(biāo)記之后內(nèi)存狀體
移動(dòng)之后的內(nèi)存狀態(tài)
清除之后內(nèi)存狀體
分代混合算法
在現(xiàn)代虛擬機(jī)(通常就是 HotSpot(TM)),使用的分代算法來(lái)處理內(nèi)存,并沒(méi)有什么新意,只是針對(duì)對(duì)象的生命周期范圍來(lái)劃分區(qū)域,不同的區(qū)域使用不同的算法。一般分為新生代和老生代,新生代由于生命不長(zhǎng),GC的時(shí)候大部分對(duì)象已經(jīng)死亡,所以有足夠的空間作為擔(dān)保,可用使用標(biāo)記-復(fù)制算法,對(duì)于老生代老生代使用標(biāo)記-清除或標(biāo)記-整理算法。
分代混合算法
Stop the world
抬腳打掃衛(wèi)生.png
想象一下,你不可能在媽媽一邊打掃衛(wèi)生的時(shí)候你一邊扔垃圾吧,她當(dāng)然希望你乖乖做在沙發(fā)上抬起腳來(lái)別動(dòng)。JVM的世界亦如此,前面我們說(shuō)道使用引用關(guān)系的根集算法來(lái)標(biāo)記對(duì)象是否無(wú)用,二這個(gè)引用關(guān)系只是某一時(shí)刻的“快照”,使用一個(gè)叫做OopMap的數(shù)據(jù)結(jié)構(gòu)來(lái)保存的。引用關(guān)系是會(huì)隨時(shí)間變化的,所以在垃圾回收器進(jìn)行垃圾回收時(shí)候就必須的有所停頓,sun把這個(gè)現(xiàn)象叫做“Stop the world ”。
所以頻繁的GC會(huì)影響性能,對(duì)象存活時(shí)間過(guò)長(zhǎng)會(huì)占用內(nèi)存,在實(shí)際開(kāi)發(fā)過(guò)程中我們?nèi)绾稳テ胶鈨?nèi)存空間和執(zhí)行效率、如何去選擇對(duì)象生命周期是非常重要的。
?為了讓學(xué)習(xí)變得輕松、高效,今天給大家免費(fèi)分享一套Java教學(xué)資源。幫助大家在成為Java架構(gòu)師的道路上披荊斬棘。需要資料的歡迎加入學(xué)習(xí)交流群:9285,05736
總結(jié)
- 上一篇: Java开发环境搭建详细步骤
- 下一篇: android camera2 采集,视