JVM內(nèi)存模型中, Heap區(qū)被分為新生代和老年代兩個區(qū)域, 新生代又分為Eden+Survivor1+Survivor2. 新生代收集算法主要使用復(fù)制算法, 老年代收集算法主要使用標(biāo)記-清理或標(biāo)記-整理算法.

堆內(nèi)存劃分
新生代在發(fā)生首次YGC的時候, Eden內(nèi)存活的對象會被復(fù)制到S1.

再發(fā)生YGC的時候, Eden內(nèi)存活的對象和S1內(nèi)存活的對象會被復(fù)制到S2, 同時清除Eden內(nèi)的對象和S1內(nèi)的對象.

再發(fā)生YGC的時候, Eden內(nèi)存活的對象和S2內(nèi)存活的對象會被復(fù)制到S1, 同時清除Eden內(nèi)的對象和S2內(nèi)的對象.

以此往復(fù)循環(huán). 生存次數(shù)超過閾值的對象進入老年代. 可以總結(jié)得出: 每次YGC發(fā)生之后, S1和S2總會有一個是空的, 這樣子的目的是避免內(nèi)存碎片化帶來的空間與性能損失. 請注意筆者畫圖的時候故意畫出間隔很大的不同內(nèi)存區(qū)域, 實際情況中這就是存活對象的內(nèi)存分布.
現(xiàn)在想象一下如果只有一個Survivor區(qū), 那么每次YGC的時候, Eden區(qū)和S區(qū)都會有內(nèi)存碎片, 這是無疑的一點, 此時如果將Eden區(qū)內(nèi)存活的對象直接復(fù)制到S區(qū), 那么內(nèi)存情況將會是如下:
(慘不忍睹...)

隨著一次次的YGC, S區(qū)內(nèi)的內(nèi)存碎片無疑會變得越來越多.內(nèi)存浪費非常嚴(yán)重. 這里有人可能會想: 我們好像也可以在每次YGC的時候, 對S區(qū)內(nèi)的對象進行重排列, 使得S區(qū)內(nèi)的對象一個個緊挨著彼此, 避免內(nèi)存碎片化. 這個想法是可以的, 但是要考慮到Y(jié)GC是JVM垃圾收集中最最最頻繁的活動. 如果每次YGC時都要花費這么多時間去重排列對象, 對象重排列相比直接復(fù)制, 是很耗時的計算. 因此劃分出兩個Survivor區(qū)域, 以空間為代價(每次都有一個S區(qū)為空)換取GC時間, 是很值得的事情. 提升了服務(wù)器響應(yīng)性.