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 (收费)