1.首先这里先说一下内存溢出和内存泄露的区别:
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak会最终会导致out of memory!
2.我们这里做一个内存溢出的例子
/**
* VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
* @author Administrator
*
*/
public class TestDump {
static class OOB {
}
public static void main(String[] args) {
List<OOB> list = new ArrayList<OOB>();
while (true) {
list.add(new OOB());
}
}
}
其中-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError是需要加的JVM启动参数
-Xms20m将堆的最小值设置为20MB,-Xmx20m将堆的最大值设置为20MB,当设置一样时即可避免堆自动扩展。
-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在内存溢出时Dump当前的内存堆转储快照以便事后进行分析。
运行结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid6256.hprof ...
Heap dump file created [27904625 bytes in 0.098 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.ArrayList.ensureCapacityInternal(ArrayList.java:208)
at java.util.ArrayList.add(ArrayList.java:440)
at com.webservie.TestDump.main(TestDump.java:18)
异常信息java.lang.OutOfMemoryError: Java heap space。解决该区域问题,一般先通过内存印象分析工具(如Eclipse Memory Analyzer)对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,
要就是先要分清楚到底是出现了内存泄露还是内存溢出。
java_pid6256.hprof就是生成的快照,可以在类所在的工程根目录下找到。
打开该快照文件,如图所示:
如果是内存泄露,可进一步通过工具查看泄露对象到GC Roots的引用链。于是就能找到泄露对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。
掌握了泄露对象的类型信息及GC Roots引用链的信息,就可以比较准确的定位出泄露代码的位置。
如果不存在泄露,就是内存中的对象确实都还必须存活着,就应该检测虚拟机的堆参数(-Xmx和-Xms),与机器物理内存对比,看看是否可以调大,从代码上检查是否存在某些
对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。