Loading

遇到OOM之后应该怎么办?

OOM产生的原因

OOM 可能产生的原因有以下几种:

  1. 内存泄漏:内存泄漏是指程序中未被使用的对象仍然占用着内存空间,导致内存无法被垃圾回收机制回收。当程序中存在大量的内存泄漏时,就会导致内存不足。

  2. 内存分配不当:如果程序中分配的内存过多或者在不需要的时候没有及时释放,就会导致内存不足。

  3. 堆内存空间不足:Java 中的对象都是在堆内存中创建的,如果程序中的对象过多或者对象本身特别大,就可能导致堆内存空间不足。

  4. 栈内存空间不足:虽然 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 (收费)
posted @ 2023-05-25 16:35  不颓废青年  阅读(52)  评论(0编辑  收藏  举报