JVM发生OOM问题定位与分析

什么是OOM?

OOM全称是Out Of Memory,即内存用完了。

为什么会有OOM?

当JVM中的内存不够分配新产生的对象时,并且垃圾回收也不能回收现有对象时,就会产生OOM异常。
一般线上发生OOM,不是内存溢出就是内存泄漏。

内存溢出
分配给JVM的内存太小,导致现在申请的内存不够,这一般只需要加大内存即可。

内存泄漏
内存泄漏一般都是程序代码写的有问题,申请的内存即没有使用也没有释放,导致垃圾回收器不能回收,慢慢的积累下来最终导致内存会消耗殆尽,加大内存可能会掩盖泄漏的问题,或者是延迟问题的发生,但是都没有彻底解决内存泄漏。

简述JAVA中产生OOM的几种类型

1、Java heap space
大多数OOM都是这个类型,内存溢出、内存泄漏等场景。
为JVM配置10M内存,申请10M,因为运行环境也需要一定内存空间,所以报Java heap space。
在这里插入图片描述

2、GC overhead limit exceeded
大概意思就是说,JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存,频繁的进行内存回收(最起码已经进行了5次连续的垃圾回收),JVM就会曝出ava.lang.OutOfMemoryError: GC overhead limit exceeded错误。

3、Permgen space
该错误表示永久代(Permanent Generation)已用满,通常是因为加载的 class 数目太多或体积太大
–一般修改-XX:MaxPermSize启动参数,调大永久代空间。

4、Metaspace
JDK1.8之后永久代被替换为Metaspcae,解决方式与上文类似。

5、Unable to create new native thread
系统内存耗尽,无法为新线程分配内存或者创建线程数超过了操作系统的限制时就会报此错误

6、Out of swap space
交换空间(swap space,虚拟内存) 不足,是由于物理内存和交换空间都不足所以导致内存分配失败。
基本上就是申请本地内存时空间不足所抛出的异常。

7、 Kill process or sacrifice child
有一种内核作业(Kernel Job)名为 Out of Memory Killer,它会在可用内存极低的情况下“杀死”(kill)某些进程。OOM Killer 会对所有进程进行打分,然后将评分较低的进程“杀死”,具体的评分规则可以参考 Surviving the Linux OOM Killer。
不同于其他的 OOM 错误, Killprocessorsacrifice child 错误不是由 JVM 层面触发的,而是由操作系统层面触发的。
原因分析
默认情况下,Linux 内核允许进程申请的内存总量大于系统可用内存,通过这种“错峰复用”的方式可以更有效的利用系统资源。
然而,这种方式也会无可避免地带来一定的“超卖”风险。例如某些进程持续占用系统内存,然后导致其他进程没有可用内存。此时,系统将自动激活 OOM Killer,寻找评分低的进程,并将其“杀死”,释放内存资源。
解决方案
1、升级服务器配置/隔离部署,避免争用。
2、OOM Killer 调优。

8、Requested array size exceeds VM limit
JVM 限制了数组的最大长度,该错误表示程序请求创建的数组超过最大长度限制。
JVM 在为数组分配内存前,会检查要分配的数据结构在系统中是否可寻址,通常为 Integer.MAX_VALUE-2。
在这里插入图片描述

9、Direct buffer memory
分配堆外内存空间不足,Java允许直接分配堆外内存,一般是出现了一些基于NIO的操作,也有可能是用到了涉及NIO的框架,比如Netty,Tomcat等。
在这里插入图片描述

发生OOM如何定位?

1、查看JVM分配的内存是否合理

通过:jmap -heap pid 这个命令查看即可。
在这里插入图片描述
如果需要调整内存大小,可以使用如下命令。

设置初始空间1024m
-Xms1024m
设置最大空间2048m
-Xmx2048m
设置初始元空间20m
-XX:MetaspaceSize=20m
设置最大元空间512m
-XX:MaxMetaspaceSize=512m

2、找到最占用内存空间的对象进行分析

设置JVM参数-XX:+HeapDumpOnOutOfMemoryError,当发生OOM时会自动dump出堆信息,然后通过eclipse mat分析哪些对象占用较多内存,以及对象之间的引用关系。

设置最大内存为32m
在这里插入图片描述

在这里插入图片描述

设置了-XX:+HeapDumpOnOutOfMemoryError参数,当发生OOM后就会生成java_pid42868.hprof文件
在这里插入图片描述
打开eclipse mat,导入java_pid42868.hprof文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实际场景内存中的对象非常多,所以我们一般会根据饼图分析哪些对象占用的内存比较可疑,然后再根据此对象的引用情况进一步分析。

对象的引入关系
在这里插入图片描述

shallow heap:对象自身占用内存大小。
retained heap:自身与所有引用对象占用内存大小。
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值