Java虚拟机内存区域溢出测试

algorain

Java虚拟机内存区域溢出测试

测试内存溢出前,先配置Debug configurations,在Arguments中的VM arguments文本框中输入对应的虚拟机启动参数。然后在进行Run执行。这样可以让虚拟机在出现内存溢出异常时Dump当前的内存堆转储快照以便事后进行分析。

Java堆溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.ArrayList;
import java.util.List;

/**
* VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
* @author Rain
*
*/
public class heapOOM {
static class OOMObject{

}
public static void main(String[] args){
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}

运行结果

1
2
3
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid4572.hprof ...
Heap dump file created [28022194 bytes in 0.087 secs]

Java堆内存的OOM异常是实际应用中常见的内存溢出异常情况。因为Java堆用于存储对象实例,只要不断的创建对象,超过最大堆的容量限制必然溢出,当出现Java堆内存溢出时,异常堆栈信息提示:java.lang.OutOfMemoryError: Java heap space

虚拟机栈和本地方法栈溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* VM Args:-Xss128k
* @author Rain
*
*/
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args)throws Throwable{
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oom.stackLeak();
}catch (Throwable e){
System.out.println("stack length:"+oom.stackLength);
throw e;
}
}
}

输出结果:

1
2
stack length:19479
Exception in thread "main" java.lang.StackOverflowError

因为内存分配原则,虚拟机栈和本机方法栈是最后分配内存的,每个线程分配到的栈容量越大,可以建立的线程数量自然越少,建立线程时就越容易把剩下的内存耗尽。如果使用虚拟机默认参数,栈深度在大多数情况下达到1000~2000完全没有问题,正常的方法调用和递归是够用了,但是在建立过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能减少最大堆和减少栈容量来换取更多的线程。

方法区和运行时常量池溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.ArrayList;
import java.util.List;
/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
* @author Rain
*
*/
public class RuntimeConstantPoolOOM {

public static void main(String[] args){
// 使用list保持着常量池引用,避免Full GC回收常量池行为
List<String> list = new ArrayList<String>();
// 10MB的permsize在integer范围内足够产生OOM
int i = 0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}

这段代码只有在JDK1.6版本运行才会报错,1.7以上逐步“去永久代”。

除此之外还有借助CGLib使方法区出现内存溢出异常,本机直接内存溢出,先不进行代码演示。

  • Title: Java虚拟机内存区域溢出测试
  • Author: algorain
  • Created at: 2018-07-04 11:39:05
  • Updated at: 2023-05-14 21:39:50
  • Link: http://www.rain1024.com/2018/07/04/article129/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments
On this page
Java虚拟机内存区域溢出测试