一、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