一、JDK1.8 JVM運行時數據區域概覽

這里介紹的是JDK1.8 JVM運行時內存數據區域划分。1.8同1.7比,最大的差別就是:元數據區取代了永久代。元空間的本質和永久代類似,都是對JVM規范中方法區的實現。不過元空間與永久代之間最大的區別在於:元數據空間並不在虛擬機中,而是使用本地內存。

二、各區域介紹
1. 程序計數器
每個線程一塊,指向當前線程正在執行的字節碼代碼的行號。如果當前線程執行的是native方法,則其值為null。
2. Java虛擬機棧

線程私有,每個線程對應一個Java虛擬機棧,其生命周期與線程同進同退。每個Java方法在被調用的時候都會創建一個棧幀,並入棧。一旦完成調用,則出棧。所有的的棧幀都出棧后,線程也就完成了使命。
3. 本地方法棧
功能與Java虛擬機棧十分相同。區別在於,本地方法棧為虛擬機使用到的native方法服務。不多說。
4. 堆

堆是JVM內存占用最大,管理最復雜的一個區域。其唯一的用途就是存放對象實例:幾乎所有的對象實例及數組都在對上進行分配。1.7后,字符串常量池從永久代中剝離出來,存放在堆中。堆有自己進一步的內存分塊划分,按照GC分代收集角度的划分請參見上圖。
4.1 堆空間內存分配(默認情況下)

老年代 : 三分之二的堆空間
年輕代 : 三分之一的堆空間
eden區: 8/10 的年輕代空間
survivor0 : 1/10 的年輕代空間
survivor1 : 1/10 的年輕代空間(from 區)
命令行上執行如下命令,查看所有默認的jvm參數
java -XX:+PrintFlagsFinal -version
輸出:


4.2 字符串常量池
JDK1.7 就開始“去永久代”的工作了。 1.7把字符串常量池從永久代中剝離出來,存放在堆空間中。
a. jvm參數配置
-XX:MaxPermSize=10m -XX:PermSize=10m -Xms100m -Xmx100m -XX:-UseGCOverheadLimit
b. 測試代碼
public class StringOomMock {
public static void main(String[] args) {
try {
List<String> list = new ArrayList<String>();
for (int i = 0; ; i++) {
System.out.println(i);
list.add(String.valueOf("String" + i++).intern());
}
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
}

5. 元數據區
元數據區取代了1.7版本及以前的永久代。元數據區和永久代本質上都是方法區的實現。方法區存放虛擬機加載的類信息,靜態變量,常量等數據。
元數據區OOM測試:
a. jvm參數配置
-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=50m
b. 測試代碼
借助cglib框架生成新類。
public class MetaSpaceOomMock {
public static void main(String[] args) {
ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MetaSpaceOomMock.class);
enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class});
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
return 1;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
});
Class clazz = enhancer.createClass();
System.out.println(clazz.getName());
//顯示數量信息(共加載過的類型數目,當前還有效的類型數目,已經被卸載的類型數目)
System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
System.out.println("active: " + loadingBean.getLoadedClassCount());
System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
}
}
}

如果是1.7的jdk,那么報OOM的將是PermGen區域。
6. 直接內存
jdk1.4引入了NIO,它可以使用Native函數庫直接分配堆外內存。
https://blog.csdn.net/bruce128/article/details/79357870

