1.內存區域划分
根據我們之前介紹的垃圾收集算法,限定商用虛擬機基本都采用分代收集算法進行垃圾回收。根據對象的生命周期的不同將內存划分為幾塊,然后根據各塊的特點采用最適當的收集算法。大批對象死去、少量對象存活的,使用復制算法,復制成本低;對象存活率高、沒有額外空間進行分配擔保的,采用標記-清除算法或者標記-整理算法。
從上面的圖可以看出, JVM區域總體分兩類,heap區和非heap區。
1.heap區又分為:
- - Eden Space(伊甸園)、
- - Survivor Space(幸存者區)、
- - Old Gen(老年代)。
2.非heap區又分:
- - Code Cache(代碼緩存區);
- - Perm Gen(永久代);
- - Jvm Stack(java虛擬機棧);
- - Local Method Statck(本地方法棧);
2.內存區域介紹
1.年輕代:
HotSpot JVM把年輕代分為了三部分:1個Eden區和2個Survivor區(分別叫from和to)。默認比例為8:1,為啥默認會是這個比例,接下來我們會聊到。一般情況下,新創建的對象都會被分配到Eden區(一些大對象特殊處理),這些對象經過第一次Minor GC后,如果仍然存活,將會被移到Survivor區。對象在Survivor區中每熬過一次Minor GC,年齡就會增加1歲,當它的年齡增加到一定程度時,就會被移動到年老代中。
因為年輕代中的對象基本都是朝生夕死的(80%以上),所以在年輕代的垃圾回收算法使用的是復制算法,復制算法的基本思想就是將內存分為兩塊,每次只用其中一塊,當這一塊內存用完,就將還活着的對象復制到另外一塊上面。復制算法不會產生內存碎片。
在GC開始的時候,對象只會存在於Eden區和名為“From”的Survivor區,Survivor區“To”是空的。緊接着進行GC,Eden區中所有存活的對象都會被復制到“To”,而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被復制到“To”區域。經過這次GC后,Eden區和From區已經被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名為To的Survivor區域是空的。Minor GC會一直重復這樣的過程,直到“To”區被填滿,“To”區被填滿之后,會將所有對象移動到年老代中。
有關年輕代的JVM參數
1)-XX:NewSize和-XX:MaxNewSize
用於設置年輕代的大小,建議設為整個堆大小的1/3或者1/4,兩個值設為一樣大。
2)-XX:SurvivorRatio
用於設置Eden和其中一個Survivor的比值,這個值也比較重要。
3)-XX:+PrintTenuringDistribution
這個參數用於顯示每次Minor GC時Survivor區中各個年齡段的對象的大小。
4).-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold
用於設置晉升到老年代的對象年齡的最小值和最大值,每個對象在堅持過一次Minor GC之后,年齡就加1。
2.old老年代
老年代,用於存放新生代中經過多次垃圾回收仍然存活的對象,也有可能是新生代分配不了內存的大對象會直接進入老年代。經過多次垃圾回收都沒有被回收的對象,這些對象的年代已經足夠old了,就會放入到老年代。
當老年代被放滿的之后,虛擬機會進行垃圾回收,稱之為Major GC。由於Major GC除並發GC外均需對整個堆進行掃描和回收,因此又稱為Full GC。
heap區即堆內存,整個堆大小=年輕代大小 + 老年代大小。堆內存默認為物理內存的1/64(<1GB);默認空余堆內存小於40%時,JVM就會增大堆直到-Xmx的最大限制,可以通過MinHeapFreeRatio參數進行調整;默認空余堆內存大於70%時,JVM會減少堆直到-Xms的最小限制,可以通過MaxHeapFreeRatio參數進行調整。
3.Code Cache代碼緩存區
它主要用於存放JIT所編譯的熱點代碼。CodeCache代碼緩沖區的大小在client模式下默認最大是32m,在server模式下默認是48m,這個值也是可以設置的,它所對應的JVM參數為ReservedCodeCacheSize 和 InitialCodeCacheSize,可以通過如下的方式來為Java程序設置。
-XX:ReservedCodeCacheSize=128m
CodeCache緩存區是可能被充滿的,當CodeCache滿時,后台會收到CodeCache is full的警告信息,如下所示:
“CompilerThread0” java.lang.OutOfMemoryError: requested 2854248 bytes for Chunk::new. Out of swap space?
4.Perm Gen(永久代) (JDK1.8之后被元空間替代)
Perm Gen全稱是Permanent Generation space,稱之為永久代,其實指的就是這個方法區。不過方法區和“PermGen space”又有着本質的區別。前者是 JVM 的規范,而后者則是 JVM 規范的一種實現,並且只有 HotSpot 才有 “PermGen space”,而對於其他類型的虛擬機,如 JRockit(Oracle)、J9(IBM) 並沒有“PermGen space”。
由於方法區主要存儲類的相關信息,Class在被Load進入這個區域后,如果應用程序LOAD很多Class的話,就很可能會出現PermGen space錯誤,比如對於動態生成類的情況比較容易出現永久代的內存溢出。它的默認大小為物理內存的1/64。
轉載地址:http://ifeve.com/jvm-yong-generation/