JVM內(nèi)存模型中, Heap區(qū)被分為新生代和老年代兩個(gè)區(qū)域, 新生代又分為Eden+Survivor1+Survivor2. 新生代收集算法主要使用復(fù)制算法, 老年代收集算法主要使用標(biāo)記-清理或標(biāo)記-整理算法.
新生代在發(fā)生首次YGC的時(shí)候, Eden內(nèi)存活的對(duì)象會(huì)被復(fù)制到S1.
再發(fā)生YGC的時(shí)候, Eden內(nèi)存活的對(duì)象和S1內(nèi)存活的對(duì)象會(huì)被復(fù)制到S2, 同時(shí)清除Eden內(nèi)的對(duì)象和S1內(nèi)的對(duì)象.
再發(fā)生YGC的時(shí)候, Eden內(nèi)存活的對(duì)象和S2內(nèi)存活的對(duì)象會(huì)被復(fù)制到S1, 同時(shí)清除Eden內(nèi)的對(duì)象和S2內(nèi)的對(duì)象.
以此往復(fù)循環(huán). 生存次數(shù)超過(guò)閾值的對(duì)象進(jìn)入老年代. 可以總結(jié)得出: 每次YGC發(fā)生之后, S1和S2總會(huì)有一個(gè)是空的, 這樣子的目的是避免內(nèi)存碎片化帶來(lái)的空間與性能損失. 請(qǐng)注意筆者畫圖的時(shí)候故意畫出間隔很大的不同內(nèi)存區(qū)域, 實(shí)際情況中這就是存活對(duì)象的內(nèi)存分布.
現(xiàn)在想象一下如果只有一個(gè)Survivor區(qū), 那么每次YGC的時(shí)候, Eden區(qū)和S區(qū)都會(huì)有內(nèi)存碎片, 這是無(wú)疑的一點(diǎn), 此時(shí)如果將Eden區(qū)內(nèi)存活的對(duì)象直接復(fù)制到S區(qū), 那么內(nèi)存情況將會(huì)是如下:
(慘不忍睹...)
隨著一次次的YGC, S區(qū)內(nèi)的內(nèi)存碎片無(wú)疑會(huì)變得越來(lái)越多.內(nèi)存浪費(fèi)非常嚴(yán)重. 這里有人可能會(huì)想: 我們好像也可以在每次YGC的時(shí)候, 對(duì)S區(qū)內(nèi)的對(duì)象進(jìn)行重排列, 使得S區(qū)內(nèi)的對(duì)象一個(gè)個(gè)緊挨著彼此, 避免內(nèi)存碎片化. 這個(gè)想法是可以的, 但是要考慮到Y(jié)GC是JVM垃圾收集中最最最頻繁的活動(dòng). 如果每次YGC時(shí)都要花費(fèi)這么多時(shí)間去重排列對(duì)象, 對(duì)象重排列相比直接復(fù)制, 是很耗時(shí)的計(jì)算. 因此劃分出兩個(gè)Survivor區(qū)域, 以空間為代價(jià)(每次都有一個(gè)S區(qū)為空)換取GC時(shí)間, 是很值得的事情. 提升了服務(wù)器響應(yīng)性.