關於JVM中Eden區、Survivor from區和Survivor to區的理解
本文主要根據《深入理解JVM》中記憶體回收策略,主要關注如下五個方面:
1:Eden區分配
2:大物件直接進入老年代
3:長期存活的物件直接進入老年代
4:動態物件年齡判定
5:空間分配擔保
首先明確新生代都是分配於Eden區的,所以Eden區是最重要也是記憶體回收最重要的管理區域,同時也是最頻繁的記憶體替換區域。我們知道JVM將記憶體根據分代策略將記憶體分為三層,新生代所佔據的記憶體、老年代所佔據的記憶體以及永久代,我們這裡不關注永久代,因為永久代是屬於方法區記憶體的部分,而新生代和老年代都是屬於堆記憶體區域的。
新生代中又繼續分為三個子塊,Eden區、Survivor from區、Survivor to區,實際上分為三個區的原因是為了方便採用複製-清除(詳情請參考深入理解JVM中記憶體回收策略)策略而採用的策略,複製策略就是將原來存在的記憶體分為兩個相等的區,使用一塊進行新生代的記憶體分配,當要GC時,則將存活的物件複製進入另一塊空閒的記憶體,然後將使用的記憶體進行清除,從而又有一個空閒區和一個使用區,並且不會有碎片問題。實際上並不需要兩個1:1的分割槽比例,因為一般存活的物件很少,所以JVM聰明的講新生代佔據的總記憶體分為Eden:Survivor from:Survivor to = 8:1:1三部分,其中Eden就用來分配新的物件記憶體,Survivor from則用於GC時的複製,那為什麼需要兩個Survivor區呢,因為複製後Survivor from區雖然現在很整齊,沒有碎片,當下一次進行回收時,Eden區和Survivor from區裡都存在需要回收的物件,則Survivor from區也會出現碎片。
那麼現在,我們看一下上述的五個部分:所有的新生代首先會在Eden區進行記憶體分配,當Eden區滿時會進行一次Minor GC操作,將Eden區進行回收,此時判斷存活的物件會被複制進入Survivor from區(年齡加1),對於大物件直接進入老年代,實際上是為了保證Eden區具有充足的空間可用的一種策略,採用-XX:PretenureSizeThreshold引數可以設定多大的物件可以直接進入老年代記憶體區域。對於長期存活的物件直接進入老年代,實際上時對Eden區到Survivor區過度的一種策略,是為了保證Eden區到Survivor區不會頻繁的進行復制一直存活的物件且對Survivor區也能保證不會具有太多的一直佔據的記憶體