实战:OutOfMemoryError异常¶
在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError(下面称OOM)异常的可能,下面通过若干实例验证异常发生的场景。
1. Java堆溢出¶
Java堆用于存储对象实例,只要不断的创建对象,并且保证GC Roots对象之间有可达路径来避免垃圾回收机制清楚这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
测试代码(Java堆内存溢出异常测试):
import java.util.ArrayList;
import java.util.List;
/*
VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
-Xms20m: 设定程序启动时占用内存大小为20M
-Xmx20m:设定程序运行期间最大可占用的内存大小为20M
-XX:+HeapDumpOnOutOfMemoryError: 让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析
*/
public class HeapOOM {
static class OOMObject{
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}
输出结果:

2. 虚拟机栈和本地方法栈溢出¶
由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,因此,对于HotSpot来说,虽然-Xoss参数(设置本地方法栈大小)存在,但实际上是无效的,栈容量只由-Xss参数设定。
两种异常: - 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常 - 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
测试代码:
/*
VM Args: -Xss128k
减少栈内存容量,结果抛出 StackOverflowError 异常,异常出现时输出的堆栈深度相应缩小
*/
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args) {
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oom.stackLeak();
}catch (Throwable e){
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
输出结果:
Exception in thread "main" java.lang.StackOverflowError
at chapter_2.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
at chapter_2.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
at chapter_2.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
at chapter_2.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:14)
3. 方法区和运行时常量池溢出¶
String.intern() 是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串中,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
书中的jdk版本为7以下,在8以上测试用例已经失效,测试用例待补充。。。
4. 本机直接内存溢出¶
书中的jdk版本为7以下,在8以上测试用例已经失效,测试用例待补充。。。