堆、虚拟机栈、本地方法栈、方法区、直接内存java
测试程序:bash
/**
* VM Args: -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
* User:wangs
* Date:2018/8/23
*/
public class HeapOOM {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
while (true) {
list.add(new Object());
}
}
}
复制代码
运行结果:数据结构
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid18148.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Heap dump file created [13355339 bytes in 0.137 secs]
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at com.thinkinjava.jvm.HeapOOM.main(HeapOOM.java:18)
复制代码
用MAT工具打开堆快照文件:jvm
“Shallow Heap”:类自己元数据的大小。“Retained Heap”:该类以及它引用的其余类所占用空间的总和xss
大概的分析步骤就是这样,关于MAT的使用,能够去多了解下。工具
/**
* VM Args:-Xss128k
* User:wangs
* Date:2018/8/27
*/
public class StackOOM {
private int stackLength = 1;
public static void main(String[] args) {
StackOOM stackOOM = new StackOOM();
try {
stackOOM.test();
} catch (Throwable e) {
System.out.println("stack length:" + stackOOM.stackLength);
throw e;
}
}
private void test() {
stackLength++;
test();
}
}
复制代码
运行结果:测试
stack length:994
Exception in thread "main" java.lang.StackOverflowError
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:25)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
复制代码
上篇文章深刻理解Java虚拟机之栈帧,介绍了栈帧,咱们来回顾一下:栈帧是保存在虚拟机栈中的,栈帧是用来存储数据和存储部分过程结果的数据结构,同时也被用来处理动态连接(Dynamic Linking)、方法返回值和异常分派(Dispatch Exception)。栈帧越大,栈深度越小。方法参数过多或者局部变量过多都会使栈深度变小,若是超过-xss设置的栈内存容量,就会致使栈溢出。ui
测试程序:spa
/*
* VM Args: -XX:PermSize=10m -XX:MaxPermSize=10m
*/
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern());
}
}
}
复制代码
在JDK1.6及以前版本中,因为常量池分配在永久代中(即方法区),咱们能够经过-XX:PermSize和-XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的容量。运行时常量池溢出:java.lang.OutOfMemoryError: PermGen space
。线程
JDK1.7常量池不在存储对象,而是存储对象的引用。修改虚拟机参数-Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
,运行结果以下:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Integer.toString(Integer.java:401)
at java.lang.String.valueOf(String.java:3099)
at com.thinkinjava.jvm.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:14)
复制代码
异常的意思是程序花在垃圾回收上的时间太多,却没有什么效果。默认的话,若是98%的时间都花在GC上而且回收了才不到2%的空间的话,虚拟机就会抛这个异常。
JDK1.8移除了永久代,类的元数据信息存储在元空间。元空间并不在虚拟机中,而是使用本地内存。所以,默认状况下,元空间的大小仅受本地内存限制,但能够经过-XX:MetaspaceSize -XX:MaxMetaspaceSize
参数来指定元空间的大小。
测试程序:
/**
* VM Args:-XX:MaxMetaspaceSize=10m
* User:wangs
* Date:2018/8/27
*/
public class MetaspaceOOM {
static ClassPool classPool = ClassPool.getDefault();
public static void main(String[] args) throws Exception {
int i = 1;
while (true){
classPool.makeClass("com.thinkinjava.jvm" + i++).toClass();
}
}
}
复制代码
运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
at javassist.ClassPool.toClass(ClassPool.java:1170)
at javassist.ClassPool.toClass(ClassPool.java:1113)
at javassist.ClassPool.toClass(ClassPool.java:1071)
at javassist.CtClass.toClass(CtClass.java:1264)
at com.thinkinjava.jvm.Metaspace.main(Metaspace.java:16)
复制代码
测试程序:
/**
* VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
* User:wangs
* Date:2018/8/27
*/
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
}
}
}
复制代码
运行结果:
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at com.thinkinjava.jvm.DirectMemoryOOM.main(DirectMemoryOOM.java:21)复制代码
若是读完以为有收获的话,欢迎点赞、关注、加公众号【Java在线】,查阅更多精彩历史!!!