遇到OOM之后应该怎么办?
OOM产生的原因
OOM 可能产生的原因有以下几种:
- 
内存泄漏:内存泄漏是指程序中未被使用的对象仍然占用着内存空间,导致内存无法被垃圾回收机制回收。当程序中存在大量的内存泄漏时,就会导致内存不足。 
- 
内存分配不当:如果程序中分配的内存过多或者在不需要的时候没有及时释放,就会导致内存不足。 
- 
堆内存空间不足:Java 中的对象都是在堆内存中创建的,如果程序中的对象过多或者对象本身特别大,就可能导致堆内存空间不足。 
- 
栈内存空间不足:虽然 Java 中的对象是在堆内存中创建的,但是每个线程都有自己的栈空间。如果栈中的局部变量和方法调用过深,就可能导致栈空间不足,从而导致程序出现内存溢出。 
遇到OOM之后应该怎么办?
构造一个简单的OOM程序
import java.util.*;
public class OOM {
    public static void main(String[] args) {
        Map<Integer,Object> cache = new HashMap<>();
        for (int i = 0; i < 128; i++) {
            cache.put(i,new Byte[1024*1024]);
        }
    }
}
运行一下
➜  temp javac OOM.java
➜  temp java -Xmx128m OOM
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at OOM.main(OOM.java:7)
先想办法拿到Heap Dump
- -XX:+HeapDumpOnOutOfMemoryError
在java启动之前添加参数-XX:+HeapDumpOnOutOfMemoryError,当JVM发生OOM时候,自动生成dump文件
➜  temp java -Xmx128m -XX:+HeapDumpOnOutOfMemoryError OOM
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid87626.hprof ...
Heap dump file created [211236627 bytes in 0.089 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at OOM.main(OOM.java:7)
➜  temp ls
OOM.class           OOM.java            java_pid87626.hprof
- jmap -dump:live,format=b,file=
将运行中java程序的堆快照dump出来,先改造一下上面的OOM程序
import java.util.*;
public class OOM1 {
    public static void main(String[] args) throws Exception{
        Map<Integer,Object> cache = new HashMap<>();
        for (int i = 0; i < 128; i++) {
            Thread.sleep(1000);
            cache.put(i,new Byte[1024*1024]);
        }
    }
}
运行OOM1
➜  temp java -Xmx128m OOM1
在上面OOM1程序运行过程中开一个新的terminal,拿到OOM1程序的pid之后通过jmap命令将快照dump到该目录下
➜  temp jps -l
29168
80485
88777 OOM1
88812 jdk.jcmd/sun.tools.jps.Jps
➜  temp jmap -dump:live,format=b,file=`pwd`/88777.hprof 88777
Dumping heap to /Users/chinese.youth/temp/88777.hprof ...
Heap dump file created [127351113 bytes in 0.074 secs]
➜  temp ls
88777.hprof         OOM.class           OOM.java            OOM1.class          OOM1.java           java_pid87626.hprof
Heap Dump 分析
MetaSapce/PermGen
java.lang.OutOfMemoryError: Prem Gen
java.lang.OutOfMemoryError: Metaspace
在java7和java7之前class对象都是放在永久代中,在java8之后class对象放在元空间中
这个空间溢出的时候基本可以确定是因为某些class对象没有被释放,很大原因可能是类加载器的泄漏。
检查JVM元空间设置参数是否过小:-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M 
Heap Space
java.lang.OutOfMemoryError: Java heap space
瞄准占用空间最大的对象
堆溢出原因
- 无法在java堆中分配对象
- 应用程序保存了无法被GC回收的对象
可以使用JProfiler工具对dump出来的存储快照进行分析
- 如果是内存泄漏,通过工具查看对象到GC Root的引用链,修复程序内存泄漏
- 如果不存在内存泄漏,可以检查程序是否存在死循环、递归等操作
分析工具
- MAT
- VisualVM
- JProfiler (收费)

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号