中對(duì)標(biāo)記刪除算法的介紹更多還是偏理論性質(zhì)的。實(shí)踐中,為了更好地滿足現(xiàn)實(shí)的場(chǎng)景及需求,還需要對(duì)算法進(jìn)行大量的調(diào)整。舉個(gè)簡(jiǎn)單的例子,我們來(lái)看下JVM需要記錄哪些信息才能讓我們得以安全地分配對(duì)象空間。
碎片及整理(Fragmenting and Compacting)
JVM在清除不可達(dá)對(duì)象之后,還得確保它們所在的空間是可以進(jìn)行復(fù)用的。對(duì)象刪除會(huì)導(dǎo)致碎片的出現(xiàn),這有點(diǎn)類似于磁盤碎片,這會(huì)帶來(lái)兩個(gè)問(wèn)題:
- 寫操作會(huì)變得更加費(fèi)時(shí),因?yàn)椴檎蚁乱粋€(gè)可用空閑塊已不再是一個(gè)簡(jiǎn)單操作。
- JVM在創(chuàng)建新對(duì)象的,會(huì)在連續(xù)的區(qū)塊中分配內(nèi)存。因此如果碎片已經(jīng)嚴(yán)重到?jīng)]有一個(gè)空閑塊能足夠容納新創(chuàng)建的對(duì)象時(shí),內(nèi)存分配便會(huì)報(bào)錯(cuò)。
為了避免此類情形,JVM需要確保碎片化在可控范圍內(nèi)。因此,在垃圾回收的過(guò)程中,除了進(jìn)行標(biāo)記和刪除外,還有一個(gè)“內(nèi)存去碎片化”的過(guò)程。在這個(gè)過(guò)程當(dāng)中,會(huì)給可達(dá)對(duì)象重新分配空間,讓它們互相緊挨著對(duì)方,這樣便可以去除碎片。下圖展示的便是這一過(guò)程:
分代假設(shè)
如前所述,垃圾回收需要完全中止應(yīng)用運(yùn)行。顯然,對(duì)象越多,回收的時(shí)間也越長(zhǎng)。那么我們能不能在更小的內(nèi)存區(qū)域上進(jìn)行回收呢?通過(guò)可行性調(diào)查,一組研究人員發(fā)現(xiàn)應(yīng)用中絕大多數(shù)的內(nèi)存分配會(huì)分為兩大類:
- 絕大部分的對(duì)象很快會(huì)變?yōu)椴豢捎脿顟B(tài)。
- 還有一些,它們的存活時(shí)間通常也不會(huì)很長(zhǎng)。
這些結(jié)論最終構(gòu)成了弱分代假設(shè)(Weak Generational Hypothesis)?;谶@一假設(shè),虛擬機(jī)內(nèi)的內(nèi)存被分為兩類,新生代(Young Generation)及老生代(Old Generation)。后者又被稱為年老代(Tenured Generation)。