OOM的排查思路

最近记录了一些java中常踩的坑、设计思路和小知识点,大家可以看看
详细记录一次接入xxl-job的踩坑路径
30s快速解决循环依赖
idea中一个小小的操作竟能解决如此多的问题
docker中的服务接入xxljob需要注意的一点
关于一次fullgc的告警分析
mysql中的int类型竟变成了它?
jpa中的字段总是自己莫名更新?
获取不到类上的注解?空指针?
学会这招,再也不怕依赖冲突!
redis的热点key还能这么处理?
领导让我设计一个任务系统
当服务重启时,大部分人没考虑这点
参数还能这么优雅校验?
文件上传报错,全局异常处理!
常见的点赞功能如何实现,如何防止刷赞

什么是OOM

简单来说,就是程序的内存不够了,挂掉了

OOM的原因

oom的原因其实就一个,内存不够了,我们要细分的就是哪里的内存不够了,以及为什么内存不够了

栈溢出

这种情况属实比较少,一般就是栈调用太深了,比如有人写了超长超长的递归方法。

方法区溢出

方法区存的都是类装载的静态结构,那什么情况会造成这种现象呢?

  1. 如果是系统启动类加载的时候出现OOM,那说明类太多了,方法区内存不够用了,就考虑是不是加大方法区的内存或者干脆加大JVM的大小,或者反向思考,是不是类真的太多了?是否需要拆服务?
  2. 如果是运行中出现这种OOM,那说明运行的时候,可能有太多类加载进去了,没错,就是反射,或者说再偶然一点,本地环境启动时,如果热部署新增太多的类也会占用方法区内存。毕竟,不管是反射还是热部署,都是破坏了双亲委派机制。

堆溢出

其实,大部分OOM场景都是堆溢出,也就是对象满了,来不及GC,内存溢出不够分配了。
那么堆中存放的又是什么呢?当然是实例对象

  1. 一个原因可能是代码中有人写了死循环创建对象,导致一瞬间创建的对象太多了
  2. 还有个原因就是某个对象的内存占用无限增长,发生了内存泄漏。比如某个service中使用了ThreadLocal但是事后没有remove,导致它维护的ThreadLocalMap越来越大。最终溢出。

发生OOM该怎么办

如果你发现服务挂掉了,去看日志发现是OOM

  1. 首先肯定是尝试重启,并且随时观察服务运行状态。如果暂时能运行,那自然是最好的,而且会排除一些情况。
  2. 不管服务起没起来,我们都要进行最关键的一步,分析为什么会出现OOM
    拿什么分析?自然需要有日志之类的记录–这里指的就是heap dump

heap dump

什么是heap dump

Heap dump文件是一个二进制文件,它保存了某一时刻JVM堆中对象使用情况。Heap Dump文件是指定时刻的Java堆栈的快照,是一种镜像文件。Heap Dump一般都包含了一个堆中的Java Objects, Class等基本信息。同时,当你在执行一个转储操作时,往往会触发一次GC,所以你转储得到的文件里包含的信息通常是有效的内容(包含比较少,或没有垃圾对象了) 。我们可以这么理解:heap dump记录内存信息的,thread dump是记录CPU信息的。

怎么得到heap dump

一般来说,两种方式

  1. 事先开启HeadDumpOnOutOfMemoryError,这样出现OOM的时候能自动留下Dump,留好第一现场。这是最推荐的方式。

JVM的启动参数中加入如下的一些参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/oom
第一个参数意思是在OOM的时候自动dump内存快照出来,第二个参数是说把内存快照存放在哪里

  1. 手工得到heap dump,这个方式就很多了,命令或者一些第三方工具,都可以获得指定java进程的heap dump。比如jdk自带的jvisualvm.exe,这个是图形化的也不用额外下载。其他方式可以自己去,有很多。
    通过jvisualvm.exe获取heap jump.

怎么分析heap dump

手把手教你进行一次OOM排查.
这个博主写的还挺详细的,总体来说就是通过查看内存使用排行啊,看错误的堆栈日志,然后进一步到代码中去寻找。
寻找的过程中额外注意这些循环什么的。

你可能感兴趣的:(JVM,java,jvm,oom,内存泄漏)