OOM排查思路

3,475 阅读5分钟

OOM排查思路

OOM排查思路一、是内存溢出Or内存泄漏?内存溢出内存泄漏二、工具的使用VisualVMJmapGC日志JVM参数三、排查过程

一、是内存溢出Or内存泄漏?

内存溢出

内存本身就太小,满足不了程序运行最小内存,则是内存溢出。

解决思路:直接加大内存。

内存泄漏

观察内存,每一次gc后都有某一些不要的对象是gc不了的,一直占着空间,导致越来越多的对象堆积在内存中得不到释放,最终内存泄漏导致内存溢出。

解决思路:应该从代码层面进行解决,不需要的对象不要建立强引用。

二、工具的使用

VisualVM

image-20210924152842932

该软件可以看到jvm进程实时的cpu、堆、calssess、线程占用情况的变化

对于某一个时刻,也支持dump出文件进行分析

一定要安装Visual GC插件,可以实时看到堆内存各个区域的变化

Jmap

Jmap是jdk自带的命令,支持对堆内存进行查看统计操作

例如:jmap -heap [pid]

image-20210924153255105

可以看到每个区一共多少大,用了多少,还剩下多少

GC日志

 #GC后堆内存状态
 Heap after GC invocations=452 (full 18):
  def new generation   total 223104K, used 8553K [0x00000000c6200000, 0x00000000d5410000, 0x00000000d96a0000)
   eden space 198336K,   0% used [0x00000000c6200000, 0x00000000c6200000, 0x00000000d23b0000)
   from space 24768K,  34% used [0x00000000d3be0000, 0x00000000d443a670, 0x00000000d5410000)
   to   space 24768K,   0% used [0x00000000d23b0000, 0x00000000d23b0000, 0x00000000d3be0000)
  tenured generation   total 495616K, used 244951K [0x00000000d96a0000, 0x00000000f7aa0000, 0x0000000100000000)
    the space 495616K,  49% used [0x00000000d96a0000, 0x00000000e85d5e00, 0x00000000e85d5e00, 0x00000000f7aa0000)
  Metaspace       used 121936K, capacity 129174K, committed 132224K, reserved 1163264K
   class space    used 15581K, capacity 17393K, committed 18304K, reserved 1048576K
 }
 ​
 ​
 #GC前堆内存状态
 {Heap before GC invocations=452 (full 18):
  def new generation   total 223104K, used 206889K [0x00000000c6200000, 0x00000000d5410000, 0x00000000d96a0000)
   eden space 198336K, 100% used [0x00000000c6200000, 0x00000000d23b0000, 0x00000000d23b0000)
   from space 24768K,  34% used [0x00000000d3be0000, 0x00000000d443a670, 0x00000000d5410000)
   to   space 24768K,   0% used [0x00000000d23b0000, 0x00000000d23b0000, 0x00000000d3be0000)
  tenured generation   total 495616K, used 244951K [0x00000000d96a0000, 0x00000000f7aa0000, 0x0000000100000000)
    the space 495616K,  49% used [0x00000000d96a0000, 0x00000000e85d5e00, 0x00000000e85d5e00, 0x00000000f7aa0000)
  Metaspace       used 121983K, capacity 129174K, committed 132224K, reserved 1163264K
   class space    used 15582K, capacity 17393K, committed 18304K, reserved 1048576K
   
 #GC时间、[空间GC前后大小]、GC使用时间
 2021-09-24T15:32:35.319+0800: 3055.215: [GC (Allocation Failure) 2021-09-24T15:32:35.319+0800: 3055.215: [DefNew: 206889K->8627K(223104K), 0.0290467 secs] 451841K->253578K(718720K), 0.0291708 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]

JVM参数

-XX:+HeapDumpOnOutOfMemoryError:出现oom时将堆dump下来

-XX:HeapDumpPath=/app/heapdump.hprof:dump文件存放位置

-Dcom.sun.management.jmxremote.authenticate=false:远程连接校验

-Dcom.sun.management.jmxremote.ssl=false:远程连接ssl方式

-Dcom.sun.management.jmxremote.port=33306:远程连接端口

-XX:NewRatio:年轻代和老年代大小比例,默认是2,即1:2

-XX:MaxTenuringThreshold:年轻代经过N次gc后还存活会进入老年代

三、排查过程

  1. 先确定是内存泄漏还是内存溢出

    • 由于项目执行任务时开始都是可以执行的,且并发执行多个任务都没有问题,而当任务执行多几次后,就会出现OOM
    • 观察每次GC后的堆内存空间,可以看到随着任务执行次数越来越多,GC执行后新生代能够清空,而老年代GC后的数据还是比较满的,则可以判定由于某些数据GC不掉,且该部分数据越来越多导致内存不足出现内存泄漏
  2. 在一次full GC后dump出堆内存文件,查看占用大内存的对象的GCRoot,可以看到被一个static引用着,因此得不到释放。

    image-20210924162438661

  3. 最终可以确定是因为程序运行过程中一直往该static Map添加元素,而用完了不去清理掉,导致对象被该Map强引用,不会被GC掉,造成内存泄漏。

\