产生oom时,可以通过查看快照的方式来分析原因,如何生成快照以及怎样查看分析该快照是本篇要讨论的内容。
1.工具:eclipse(安装Memory Analyzer 插件)
2.java参数:
-XX:+PrintGCDetails -Xloggc:/data/logs/JavaDemo/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/JavaDemo -Xms1m -Xmx1m、
其中:
-XX:+PrintGCDetails 打印gc日志
-Xloggc:/data/logs/JavaDemo/gc.log gc日志的地址
-XX:+HeapDumpOnOutOfMemoryError 出现内存溢出异常时dump出当前的内存转储快照
-XX:HeapDumpPath=/data/logs/JavaDemo 指定快照的存放位置
-Xms1m jvm初始内存
-Xmx1m jvm最大内存
此处设置jvm内存较小是为了之后模拟oom时更快报错。平时项目里不用这么设置。
3.oom现场
1)产生oom的测试代码
package common; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * Created by zuzhaoyue on 18/6/12. */ public class OOMTest { //java堆溢出 // -XX:+PrintGCDateStamps -Xloggc:/data/logs/JavaDemo/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/JavaDemo -Xms1m -Xmx1m public void headSpaceOOM(){ List list = new ArrayList<>(); while(true) { list.add(new OOMTest()); } } public static void main(String args[]) { new OOMTest().headSpaceOOM(); } }
执行上段代码结果如下
java.lang.OutOfMemoryError: Java heap space
Dumping heap to /data/logs/JavaDemo/java_pid42294.hprof ...
Heap dump file created [2758120 bytes in 0.029 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
...
2)用hprof快照文件定位
使用eclipse,File->OpenFile->选择/data/logs/JavaDemo/java_pid42294.hprof,界面如下
可以看到有一个占了927.4kb的对象,往下拉可以看到工具猜测的问题点,
点击,Details基本上就能定位到问题了:
显示有一个对象占用了78.35%的jvm内存,再看stacktrace
哪一行都指出来了,太明显了。
当然通过观察里面的对象的大小也可以看出来,点击左数第三个按钮:
可以看到所有对象的大小,如下:
第一个占了大部分内存的对象,点开:
可以看到占了很多内存的对象是一个OOMTest数组,这样也能基本定位到问题~