带着问题阅读
- 如何制造OutOfMemory?
- jvm启动参数怎么设置?
- 如何根据异常信息判断哪个区域发生内存溢出?
- 发生内存溢出后如何解决?
- 方法区从JDK1.6到JDK1.8都经历了什么?
- JDK1.8新增的Metaspace是什么东西?
导语
上一讲我们已经了解了Java虚拟机的内存模型,既然我们知道各个内存区域存储的内容,那么只要在代码上做一些“手脚”,就可以制造出内存溢出(OutOfMemory)异常,这就是我们这一讲要做的事。
在机器上制造各种OutOfMemory异常,目的有三:
- 通过代码验证上一讲所讲的各个运行时区域所存储的内容;
- 帮助读者在实际项目中遇到内存溢出异常时,能够根据异常信息快速判断是哪个区域的内存溢出,知道什么样的代码可能导致这些区域内存溢出,以及出现异常后该如何处理。
- 以后大家遇到OutOfMemory,把异常环境信息在这篇文章搜索一下,就可以找到分析和解决的思路。
本文是Effective Java专栏Java虚拟机专题的第三讲,如果你觉得看完之后对你有所帮助,欢迎订阅本专栏,也欢迎您将本专栏分享给你身边的工程师同学。
在学习本节课程之前,建议您了解一下以下知识点:
下文中代码的开头的注释都说明了执行代码时要设置的虚拟机启动参数。如果您使用控制台命令来执行,直接在java命令后面加上启动参数即可;如果是通过Eclipse IDE来执行,则在Debug/Run Configuration - Arguments页签进行设置:
Java堆溢出
通过上一讲的讲解,我们已经知道,Java堆是用于存储对象实例的,因此,只要我们不断创建对象,并且保证对象不被垃圾回收机制清除,那么当堆中对象的大小超过了最大堆的容量限制,就会出现堆内存溢出。
下面这段代码,将Java堆的大小设置为20MB,并且不可扩展(通过将堆的最小值-Xms参数和最大值-Xmx参数设置为相等的20MB);通过参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时生成当前内存堆的快照,以便事后进行分析。
/**
* VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*/
public class HeapOOM {
static class OOMObject {
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while (true) {
list.add(new OOMObject());
}
}
}
运行结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10284.hprof ...
Heap dump file created [27866984 bytes in 0.144 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:242)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
at java.util.ArrayL