目录java
应用程序出现OOM异常,你是否仍然经过看日志的方式去排查问题(该方式定位解决问题是大几率的巧合而已)?正确的排查方案是进行dump文件分析,你知道为何吗?linux
首先说一下,本人在开发中遇到的OOM异常基本也是经过看log日志去定位的(不少OOM异常是由于出现死循环或者查询返回的数据量多大,没有分页等等,经过异常日志咱们确实能很快定位,但这不是正确的姿式。),只是碰巧恰好日志打印的异常栈信息就是对应的代码问题。
不少博客也说了,定位OOM异常经过分析dump日志,所以深表疑惑,为何明明看log日志就能解决的非要去分析dump日志,网上也没有检索到满意的答案,问了身边的不少开发,也仅仅说dump进行性能分析,log日志进行异常排查。在我几度深思中,忽然开窍,特此写下缘由。app
请看大屏幕:jvm
public class OOMDump { static class OOMIntsmaze { public byte[] placeholder = new byte[64 * 1024]; } public static void fillHeap(ArrayList<OOMIntsmaze> list, int num) throws Exception { for (int i = 0; i < num; i++) { list.add(new OOMIntsmaze()); System.out.println(i); } } public static void main(String[] args) throws Exception { ArrayList<OOMIntsmaze> list = new ArrayList<OOMIntsmaze>(); fillHeap(list,131); Thread.sleep(20000000); } }
咱们配置jvm参数以下 -Xmx10M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d://
当fillHeap(list,131)时,程序正常执行;当fillHeap(list,132)时,程序就会报OOM异常:性能
130 java.lang.OutOfMemoryError: Java heap space Dumping heap to d://\java_pid10000.hprof ... Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at cn.intsmaze.dump.OOMDump$OOMIntsmaze.<init>(OOMDump.java:27) at cn.intsmaze.dump.OOMDump.fillHeap(OOMDump.java:34) at cn.intsmaze.dump.OOMDump.main(OOMDump.java:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) Heap dump file created [10195071 bytes in 0.017 secs] at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
经过异常日志咱们能够看到,是由于代码
at cn.intsmaze.dump.OOMDump.fillHeap(OOMDump.java:34)
list.add(new OOMIntsmaze());
致使的问题,经过日志所见即所得,我立马解决了问题,为何要看dump日志呢?我有病啊。spa
其实否则,骚年。假如main方法以下,执行操作系统
public static void main(String[] args) throws Exception { ArrayList<OOMIntsmaze> list = new ArrayList<OOMIntsmaze>(); fillHeap(list,131); Map<String,OOMIntsmaze> map=new HashMap<String,OOMIntsmaze>(); map.put("LIUYANG",new OOMIntsmaze()); map.put("intsmaze",new OOMIntsmaze()); Thread.sleep(20000000); }
这个时候咱们经过异常日志发现是由于map.put("LIUYANG",new OOMIntsmaze());致使的,找到代码发现,map里面才插入了一条数据,没有出现死循环,怎么会致使OOM异常了,真是活久见了。.net
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at cn.intsmaze.dump.OOMDump$OOMIntsmaze.<init>(OOMDump.java:27) at cn.intsmaze.dump.OOMDump.main(OOMDump.java:49) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
设置10M咱们能够发现list添加132各个元素时会发生OOM,这个时候咱们向list添加131个元素,而后执行map添加,发现map添加一个元素就报错。此时的oom异常日志定位的是map添加元素致使的。
可是真实状况不是的,由于看代码也会发现map只添加了2个元素,怎么会是他形成的。map的添加只是恰好此时jvm内存达到容量上限了。
因此要找到根本问题,是须要经过dump文件分析OOM时,各个对象的容量状态。
并且实际状况中,map.put()的代码并不会向上面示例同样和list.add()代码放在一块,而是位于不一样的包下,不一样的业务流程中。这个时候看log日志去定位基本不可能了。
可是为何你们出行OOM异常仍是经过看log日志并且定位的位置是正确的。只是由于向list.add这种循环中,一直在执行,基本大几率是他触发的。线程
因此为了防患于未然,程序猿在开发的时候,必定要配置jvm启动参数HeapDumpOnOutOfMemoryError。
参数-XX:+HeapDumpOnOutOfMemoryError可让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便过后进行分析
日志
有些时候,咱们的应用程序宕机,既不会打印log平常信息,dump文件也不会生成,这个时候基本就是linux系统杀掉了咱们的应用程序进程。
messages 日志是核心系统日志文件。它包含了系统启动时的引导消息,以及系统运行时的其余状态消息。在messages里会出现如下信息
out of memory:kill process 8398(java) score 699 or sacrifice child killed process 8398,UID 505,(java) total-vm:2572232kB,anno-rss:1431292kB,file-rss:908kB
oom killer是linux系统的一个保护进程,当linux系统所剩的内存空间不足以知足系统正常运行时,会触发。oomkiller执行时,会找出系统全部线程的score值最高的那个pid,而后干掉。
这里咱们能够看到,JAVA进程的确是被LINUX的oom killer干掉了。
咱们的应用程序和日志都只能记录JVM内发生的内存溢出。若是JVM设置的堆大小超出了操做系统容许的内存大小,那么操做系统会直接杀死进程,这种状况JVM就没法记录本次操做。
Linux对于每一个进程有一个OOM评分,这个评分在/proc/pid/oom_score文件中。例如/proc/8398/oom_score,若是不但愿杀死这个进程,就将oom_adj内容改成-17。
更多关于linux的oom killer机制请自行百度检索。
最正确的姿式:首先调整JVM的heap大小,使得JVM的OOM优先于操做系统的OOM出现,接着设置运行参数,在发生OOM的时候输出heapdump文件。
请上公交车:JVM各类内存溢出是否产生dump https://blog.csdn.net/stevendbaguo/article/details/51366181