发生OOM了,你知道是什么原因吗,又该怎么解决呢?


大家好,我是风云,欢迎大家关注我的博客 或 微信公众号【笑看风云路】,在未来的日子里我们一起来学习大数据相关的技术,一起努力奋斗,遇见更好的自己!

扫码进,更快捷:
笑看风云路

前言

撸java代码的同学,多多少少都会碰到内存溢出(OOM)的场景,但是造成OOM原因却不止一个。今天就来总结一下常见的OOM的原因以及解决方案。

1、堆内存不足(Java heap space)

原因:

  1. 代码中可能存在大对象分配,通常是一个大树组。
  2. 可能存在内存泄露,导致多次GC之后,还是无法找到一块足够大的内存容纳当前对象,常见于使用了File等资源没有回收。
  3. 超出预期的访问量、数据量,通常是上游系统请求流量飙升,常见于各类促销、秒杀活动,可以结合业务流量指标排查是否有尖状峰值。

解决方案:

  1. 针对大部分的情况,通常只需要通过-Xmx参数调高JVM堆内存即可。如果仍然没有解决,可以参考下面几种情况进行处理。
  2. 如果是超大对象,检查其合理性,比如是否一次查询了数据库全部结果,而没有做结果数限制。
  3. 如果是业务峰值压力,可以考虑添加机器资源,或者做限流降级操作。
  4. 如果是内存泄露,需要找到持有对象,修改代码设计,比如关闭没有释放的连接。

2、永久代空间/元空间(Permgen space/ metaspace)

原因:

  1. 永久代是HotSot虚拟机对方法区的具体实现,存放被虚拟机加载的类信息、常量池、静态变量,JIT编译后的代码等
  2. Perngen的使用量和加载到内存的class的数量/大小正相关

解决方案:

  1. 检查是否永久代空间(启动参数:-XX:MaxPermSize)或者元空间(启动参数:-XX:MaxMetaspaceSize)设置的过小。
  2. 检查代码中是否存在大量反射操作
  3. dump之后通过mat检查是否存在大量由于反射生成的代理类
  4. 应用部署时报错,很可能没有重启应用,导致加载了多份class信息,重启JVM即可解决

3、GC overhead limit exceeded

原因:

  1. 当java进程花费98%以上时间来做GC并且回收了不到2%的堆内存时会抛出此异常。
  2. 堆内存太小

解决方案:

  1. 检查项目中是否有大量的死循环或者使用大内存的代码,优化代码
  2. dump内存,检查是否存在内存泄露,如果没有,加大内存。

4、方法栈溢出(Unable to create new native thread)

原因:

  1. 线程数超过操作系统最大线程数ulimit限制
  2. 线程数超过kernal.pid_max
  3. native 内存不足

解决方案:

  1. 升级配置,为机器提供更多内存
  2. 降低Java heap space大小
  3. 修复应用程序的线程泄露问题
  4. 限制线程池大小
  5. 使用-Xss参数减少线程栈大小
  6. 调高OS层面的线程最大数:执行ulimit -a 查看最大线程数限制,使用ulimit -u xx 调整最大线程数限制

5、swap区溢出(Out of swap space)

该错误表示所有可用的虚拟内存已被耗尽。虚拟内存(Virtual Memory)由物理内存(Physical)和交换空间(Swap Space)两部分组成。当运行时程序请求的虚拟内存溢出时就会报 Out of swap space错误。

原因:

  1. 地址空间不足
  2. 物理内存已耗光
  3. 应用程序的本地内存泄露,例如不断申请本地内存,却不释放
  4. 执行jmap -histo:live 命令,强制执行Full GC;如果执行几次后内存明显下降,则基本确认为Direct ByteBuffer问题

解决方案:

  1. 升级地址空间为64bit
  2. 使用Arthas检查是否为Inflater/Deflater 解压问题,如果是,则显示调用end方法
  3. Direct ByteBuffer问题可以通过启动参数–XX:MaxDirectMemorySize降低阈值
  4. 加大swap分区大小或者加大机器内存大小
  5. 隔离部署,避免争抢

6、分配超大数组(Requested array size exceeds VM limit)

原因:

这种情况一般是由于不合理数组分配请求导致的,在为数组分配内存之前,JVM会执行一项检查。要分配的数组在该平台是否可以寻址,如果不能寻址就会抛出这个错误。

解决方案:

检查代码中是否有创建超大数组的地方

7、Direct buffer memory

Java允许应用程序通过Direct ByteBuffer直接访问堆外内存,许多高性能程序通过Direct ByteBuffer结合内存映射文件(Memory MappedFile)实现高速IO

原因:

Direct ByteBuffer的默认大小为64MB,一旦使用超出限制,就会抛出Direct buffer memory错误。

解决方案:

Java只能通过ByteBuffer.allocateDirect方法使用DirectByteBuffer,因此,可以通过Arthas等在线诊断工具拦截该方法进行排查。

  1. 检查是否直接或间接使用了NIO,如netty,jetty等
  2. 通过启动参数-XX:MaxDirectMemorySize调整Direct ByteBuffer上限值
  3. 检查JVM参数是否有-XX:+DisableExplicitGC选项,如果有去掉,因为该参数会使System.gc()失效
  4. 检查堆外内存的代码,确认是否存在内存泄露;或者通过反射调用sun.misc.Cleaner的clean() 方法来主动释放Direct ByteBuffer持有的内存空间。
  5. 内存容量确实不够的,升级配置

8、Kill process or sacrifice child

有一种内核作业(Kernel Job)名为 Out of Memory Killer,它会在可用内存极低的情况下“杀死”(kill)某些进程。OOM Killer 会对所有进程进行打分,然后将评分较低的进程“杀死”,具体的评分规则可以参考 Surviving the Linux OOM Killer。

不同于其他的 OOM 错误,Kill processorsacrifice child错误不是由 JVM 层面触发的,而是由操作系统层面触发的。

原因:

默认情况下,Linux 内核允许进程申请的内存总量大于系统可用内存,通过这种“错峰复用”的方式可以更有效的利用系统资源。

然而,这种方式也会无可避免地带来一定的“超卖”风险。例如某些进程持续占用系统内存,然后导致其他进程没有可用内存。此时,系统将自动激活 OOM Killer,寻找评分低的进程,并将其“杀死”,释放内存资源。

解决方案:

  1. 升级服务器配置/隔离部署,避免争用。
  2. OOM Killer 调优。

结语

好了,今天就为大家分享到这里了。如果本文对你有帮助的话,欢迎点赞&收藏&分享,这对我继续分享&创作优质文章非常重要。感谢🙏🏻

–END–

非常欢迎大家加我个人微信,有关大数据的问题我们一起讨论。
在这里插入图片描述

扫码上方二维码,加我微信

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当遇到内存不足(OOM)的问题时,可以采取以下步骤进行排查和解决: 1. 确认OOM错误:查看系统日志或应用程序日志,确认是否发生OOM错误。通常,OOM错误会在日志中显示为"Out of memory"或"java.lang.OutOfMemoryError"等。 2. 分析内存使用情况:使用监控工具(如top、htop)或分析工具(如jstat、jmap)来观察系统或应用程序的内存使用情况。检查是否存在内存泄漏或者内存使用过高的情况。 3. 调整JVM参数:如果是Java应用程序发生OOM,可以尝试调整JVM参数来增加可用内存。常见的参数包括-Xmx(最大堆内存大小)和-Xms(初始堆内存大小),可以根据应用程序的需求进行调整。 4. 优化代码:检查应用程序的代码,确保没有存在内存泄漏或者不合理的内存使用。可以通过使用合适的数据结构、及时释放资源、避免大对象等方式来优化代码。 5. 增加服务器资源:如果以上方法无法解决OOM问题,可以考虑增加服务器的物理内存或者升级到更高配置的服务器。 6. 使用分布式系统:如果单台服务器无法满足应用程序的内存需求,可以考虑使用分布式系统,将应用程序分散到多台服务器上,从而充分利用集群的内存资源。 7. 调整应用程序逻辑:如果应用程序需要处理大量数据或者复杂计算,可以考虑优化算法或者分批处理数据,以减少内存的使用。 在解决OOM问题时,需要根据具体情况进行分析和调整。如果问题比较复杂,可以借助性能分析工具或者咨询专业的开发人员来进行排查和解决

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

笑看风云路

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

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

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

打赏作者

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

抵扣说明:

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

余额充值