深入理解JVM學習筆記(二十六、JVM 記憶體分配----優先分配到eden&空間分配擔保)
一、優先分配到eden
我們寫一個程式來驗證物件優先分配到eden,原始碼如下:
package com.zjt.test.jvm008;
public class Main {
public static void main(String[] args) {
byte [] b1 = new byte[4 * 1024 * 1024];
}
}
在執行main方法前進行如下配置,配置做用是讓控制檯顯示JVM資訊:
執行結果如下圖所示:
從圖中可以看出年輕代一共有38400K空間,6758K已經被使用。其中eden區被使用20%,其餘區域使用率都是0。因此可以看出來 物件記憶體是有限分配至年輕代的eden區域的。
二、JVM對垃圾回收器的選擇
仔細觀察年輕代資訊前方關鍵字是PSYoungGen。其中PS是指Parallel Scavenge,說明YoungGen使用的是Parallel收集器。而老年代中的PAROldGen說明老年代使用的是parnew收集器。
我們也可以用過配置來修改預設垃圾回收器。如下圖所示:
執行後結果如下圖
那麼問題來了,為什麼預設使用的是Parallel收集器呢,因為JVM內部機制判定當執行環境為Server環境時就使用Parallel收集器,而JVM對Server環境要求太低了,只需要2G+記憶體和多核CPU即可。因此絕大多數機器都會被JVM預設成Server環境。
檢視自己環境也可以在CMD下執行java -version檢視:
三、空間分配擔保
我們按照下圖要求對記憶體進行配置
配置如下圖所示
我們在程式中定義四個物件,其中三個2M,一個4M。執行程式沒檢視GC顯示。
程式如下:
package com.zjt.test.jvm008; public class Main { public static void main(String[] args) { byte [] b1 = new byte[2 * 1024 * 1024]; byte [] b2 = new byte[2 * 1024 * 1024]; byte [] b3 = new byte[2 * 1024 * 1024]; byte [] b4 = new byte[4 * 1024 * 1024]; System.gc(); } }
GC顯示如下圖:
從上圖可以看出。,eden中4M為我們程式中定義的最後一個物件,老年代佔用的6M是我們先前定義的3個2M物件。下面我們分析下為什麼會出現上圖所示。
1、3個2M物件進入Eden,Eden使用了6M,剩餘2M可用
2、一個4M物件進入Eden,Eden記憶體不夠用,因此要進行GC,如下圖
3、第二步要執行的GC會將物件往Survival區域放,因為新生代一共就10M,而Eden就用了8M。那兩個Survival區域每個只有1M,這是放不下我們物件的。因此會觸發空間分配擔保策略。從老年代借用6M記憶體存放三個2M的物件。