- 只要JVM無(wú)法為新創(chuàng)建的對(duì)象分配空間,就肯定會(huì)觸發(fā)新生代GC,比方說(shuō)Eden區(qū)滿了。因此對(duì)象創(chuàng)建得越頻繁,新生代GC肯定也更頻繁。
- 一旦內(nèi)存池滿了,它的所有內(nèi)容就會(huì)被拷貝走,指針又將重新歸零。因此和經(jīng)典的標(biāo)記(Mark),清除(Sweep),整理(Compact)的過(guò)程不同的是,Eden區(qū)和Survivor區(qū)的清理只涉及到標(biāo)記和拷貝。在它們中是不會(huì)出現(xiàn)碎片的。寫指針始終在當(dāng)前使用區(qū)的頂部。
- 在一次新生代GC事件中,通常不涉及到年老代。年老代到年輕代的引用被認(rèn)為是GC的根對(duì)象。而在標(biāo)記階段中,從年輕代到年老代的引用則會(huì)被忽略掉。
- 和通常所理解的不一樣的是,所有的新生代GC都會(huì)觸發(fā)“stop-the-world”暫停 ,這會(huì)中斷應(yīng)用程序的線程。對(duì)絕大多數(shù)應(yīng)用而言,暫停的時(shí)間是可以忽略不計(jì)的。如果Eden區(qū)中的大多數(shù)對(duì)象都是垃圾對(duì)象并且永遠(yuǎn)不會(huì)被拷貝到Survivor區(qū)/年老代中的話,這么做是合理的。如果恰好相反的話,那么絕大多數(shù)的新生對(duì)象都不應(yīng)該被回收,新生代GC的暫停時(shí)間就會(huì)變得相對(duì)較長(zhǎng)了。
現(xiàn)在來(lái)看新生代GC還是很清晰的—— 每一次新生代GC都會(huì)對(duì)年輕代進(jìn)行垃圾清除。
老年代GC與Full GC
你會(huì)發(fā)現(xiàn)關(guān)于這兩種GC其實(shí)并沒有明確的定義。JVM規(guī)范或者垃圾回收相關(guān)的論文中都沒有提及。不過(guò)從直覺來(lái)說(shuō),根據(jù)新生代GC(Minor GC)清理的是新生代空間的認(rèn)識(shí)來(lái)看,不難得出以下推論(這里應(yīng)當(dāng)從英文出發(fā)來(lái)理解,Minor, Major與Full GC,翻譯過(guò)來(lái)的名稱已經(jīng)帶有明顯的釋義了):
- Major GC 清理的是老年代的空間。
- Full GC 清理的是整個(gè)堆——包括新生代與老年代空間
不幸的是這么理解會(huì)有一點(diǎn)復(fù)雜與困惑。首先——許多老年代GC其實(shí)是由新生代GC觸發(fā)的,因此在很多情況下兩者無(wú)法孤立來(lái)看待。另一方面——許多現(xiàn)代的垃圾回收器會(huì)對(duì)老年代進(jìn)行部分清理,因此,使用“清理”這個(gè)術(shù)語(yǔ)則顯得有點(diǎn)牽強(qiáng)。
那么問(wèn)題就來(lái)了,先別再糾結(jié)某次GC到底是老年代GC還是Full GC了, 你應(yīng)該關(guān)注的是這次GC是否中斷了應(yīng)用線程還是能夠和應(yīng)用線程并發(fā)地執(zhí)行 。
即便是在JVM的官方工具中,也存在著這一困擾。通過(guò)一個(gè)例子來(lái)說(shuō)明應(yīng)該更容易理解一些。我們用兩款工具來(lái)跟蹤某個(gè)運(yùn)行著CMS回收器的JVM,來(lái)比較下它們的輸出有什么不同: