当前位置: 首页 > news >正文

JVM OOM问题排查与解决思路

今天咱们来聊聊让无数 Java 开发者头疼的 JVM OOM(Out Of Memory,内存溢出)问题。

目录

一、JVM OOM 到底是什么?

二、OOM 为啥会发生?

三、OOM 都有哪些类型呢?

1.堆内存溢出

2.永久代/原空间溢出

3.栈内存溢出

4.直接内存溢出

四、排查 OOM 的“杀手锏”

通过MAT作为示例定位问题

0.获取dump文件

1.打开Heap Dump文件:启动MAT并打开Heap Dump文件(.hprof)

2.运行Leak Suspects Report :MAT可自动生成一个内存泄漏(Leak Suspects Report),该报告指出可能内存泄漏路径

3.分析Dominators Tree:该视图显示了占用最多的内存对象及其引用。通过1它,可找到最大的内存消耗者。

4.查看Histogram:列出所有对象的实例数和总大小,帮助识别那种类型的对象占用最多的内存

5.检查GC Roots:确定对象为什么没有被垃圾回收,可查看对象到GC Roots的引用链

6.分析引用链:通过分析对象的引用链,可确定是什么持有了这些对象的引用,导致它们无法被回收

通过jvisualvm定位OOM问题

通过Arthas工具定位问题

五、总结


一、JVM OOM 到底是什么?

简单来说JVM OOM就是Java虚拟机的内存用完了,而且垃圾回收器(GC)也无能为力,没办法再为新对象分配内存,于是抛出了错误。这就好比你开着一辆车,邮箱里的油已经耗尽,但你还想继续加速,结果只能熄火。

二、OOM 为啥会发生?

OOM的原因多种多样,但归根结底就两个字————“不够用”。具体来说,有这么几种常见情况:

1.内存分配不足:JVM初始化时。堆内存、永久代(或元空间)等区域分配得太小,根本不够业务跑。     比如,你的应用要处理海量数据,但堆内存只给了128MB,这不就是“杯水车薪”嘛。这种我们称不上bug,只是亦或是称为 “巧妇难为无米之炊”吧

2.大对象申请:一次性申请的内存太大,超出了JVM的承受范围。     比如,试图一次性加载一个几GB的文件到内存中,JVM根本就装不下。

3.内存泄漏:程序中某些地方申请了内存,但是因为代码逻辑错误,这些已经无用的内存却一直被引用,得不到释放,就像一个无底洞,不断吞噬JVM的内存。

4.代码问题:程序里某些对象被频繁创建,用完却没有被及时释放,导致内存被一点点占用,比如,一个定时任务不断往缓存中赛数据,但从来没清理过,时间一长,内存就被塞满了。

三、OOM 都有哪些类型呢?

1.堆内存溢出

这是OOM最常见的形式

错误信息是:

java.lang.OutOfMemoryError: Java heap spac

堆内存是JVM里存放对象实例的地方,如果堆内存满了,垃圾回收器又没办法清理足够的空间,就会触发这个错误。

2.永久代/原空间溢出

报错信息:

java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: Metaspace

在JDK7及以下版本中,永久代(PermGen)用于存放类的元数据、常量池等信息。如果应用加载了大量类,比如使用了动态代理、字节码操作等技术,永久代很容易被撑爆,抛出错误。从JDK 8 开始,永久代被原空间(Metaspace)取代,但原理类似。

核心原因:生成大量动态类

 1.使用大量动态生成类的框架,如ORM框架,动态代理技术、热部署工具等

 2.程序代码中大量使用,反射在大量使用时,由于使用缓存的原因,会导致ClassLoader和他引用的Class等对象不能被回收。

3.栈内存溢出

报错信息:

java.lang.OutOfMemoryError : unable to create new native Thread

栈内存是线程私有的,用于存放方法调用的局部变量、操作数栈等信息。如果一个方法调用链太深,比如递归调用过深,或者方法里的局部变量过多,栈内存就会溢出,虽然名字里面又“Overflow”,但本质也是OOM的一种。

4.直接内存溢出

报错信息:

java.lang.OutOfMemoryError: Direct buffer memory

Java堆外内存OOM值的是Java直接使用非堆内存耗尽导致的,这部分内存主要用于Java NIO库,允许Java程序以更接近操作系统的方式管理内存,常用于高性能缓存、大型数据处理等场景。

四、排查 OOM 的“杀手锏”

1.启动JVM诊断选项

在启动应用时,加上这些参数

-XX:+HeapDumpOnOutOfMemoryError       //  指示JVM在遇到OOM错误时生成堆转储文件

-XX:HeapDumpPath=/path/to.dump            //指定堆转储文件的存储路径,可以自定义路径和文件名

-Xlog:gc*(JVM 9及以上)

-XX:PrintGCDeails -Xloggc:/path/to/gc.log(JVM8及以下)

这些参数可以让JVM在OOM的时生成内存堆转储文件和GC日志,帮助我们分析问题。

2. 分析错误日志

仔细查看应用日志和OOM错误堆栈信息,看看哪个内存区域出了问题。

3.分析堆转储文件

用JVisualIVM、MAT这些工具打开堆转储文件,找出内存占用大户,看看是不是有点内存泄漏。

当应用抛出OOM并且根据上述设置生成了堆转储文件后,使用Heap Dump分析工具来分析文件,常用的工具有:

 Eclipse Memory Analyzer(MAT):    一个强大的]ava堆分析工具,可以帮助识别内存泄漏和査看内存消耗等情况。


VisuaIVM:  除了监控功能外,也支持加载和分析Head Dump文件。

4.检查GC日志

分析GC日志,看看垃圾回收的概率、暂时时间和各内存区的使用情况,判断是不是垃圾回收出了问题。

5.代码审查和优化

从代码层找原因,看看是不是有缓存没清理、静态集合不断增长等内存泄漏问题。发现问题后,优化代码,减少对象创建,及时释放内存。

通过MAT作为示例定位问题

0.获取dump文件

注意导出文件占用内存很大的时候,可能会导不出来

方式一:提前配置JVM参数,在系统挂了后会在指定目录下生成dump文件

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=./ (导出路径)

方式二:使用命令行导出

jmap -dump:format=b,file=demo.hprof <pid>

1.打开Heap Dump文件:启动MAT并打开Heap Dump文件(.hprof)

2.运行Leak Suspects Report :MAT可自动生成一个内存泄漏(Leak Suspects Report),该报告指出可能内存泄漏路径

3.分析Dominators Tree:该视图显示了占用最多的内存对象及其引用。通过1它,可找到最大的内存消耗者。

4.查看Histogram:列出所有对象的实例数和总大小,帮助识别那种类型的对象占用最多的内存

5.检查GC Roots:确定对象为什么没有被垃圾回收,可查看对象到GC Roots的引用链

6.分析引用链:通过分析对象的引用链,可确定是什么持有了这些对象的引用,导致它们无法被回收

ps:授人以鱼不如授人以渔,en!有那味啦

MAT下载教程:

mac pro m1:安装dump文件内存分析工具——MAT_dump文件分析工具-CSDN博客

MAT使用教程~:线上又 OOM 了 ,教你快速定位问题~-腾讯云开发者社区-腾讯云

通过jvisualvm定位OOM问题

 通过jvisualvm工具装载dump文件

查看内存占用最高的业务对象,并找到GCRoot并查看线程栈从定位问题

通过Arthas工具定位问题

执行如下命令下载arthas-boot.jar,再用java -jar命令启动:

wgethttps://arthas.aliyun.com/arthas-boot.jar; java-jararthas-boot.jar

arthas-boot是Arthas的启动程序,它启动后,会列出所有的Java进程,用户可以选择需要诊断的目标进程。

使用dashboard 命令可以查看当前系统的实时数据面板。可以查看到CPU、内存、GC、运行环境等信息。

使用 sc 命令来查找JVM里已加载的类,通过-d参数,可以打印出类加载的具体信息,很方便查找类加载问题。

五、总结

JVM OOM 是一个复杂但常见的问题,它可能出现在堆内存、永久代/元空间、栈内存或直接内存等区域。排查 OOM 的关键在于启用诊断选项(如堆转储和 GC 日志)、分析错误日志和堆转储文件、检查垃圾回收日志。解决 OOM 的方法包括增加内存、优化代码、调优垃圾回收器参数和管理外部资源。持续监控和预警机制可以有效预防 OOM 问题的发生。

http://www.dtcms.com/a/348078.html

相关文章:

  • Meta AI 剧变:汪滔挥刀重组,Llama 开源路线告急,超级智能梦碎还是重生?
  • 96、23种设计模式之原型模式(5/23)
  • STM32 USB 之大坑
  • ubuntu中网卡的 IP 及网关配置设置为永久生效
  • Ubuntu24.04环境下causal_conv1d和mamba_ssm安装
  • 嵌入式八股文面试题总结(QT、RTOS、Linux、ARM、C/C++)(持续更新)
  • QT-布局管理器
  • 音视频面试题集锦第 32 期
  • C语言指针5
  • 使用虚幻引擎5(UE5)开发类似《原神》的开放世界游戏:从技术架构到实践指南
  • LeetCode-542. 01 矩阵
  • (LeetCode 每日一题) 1493. 删掉一个元素以后全为 1 的最长子数组 (双指针)
  • 03-鸿蒙架构与编程模型
  • ChainVault:重塑亚洲黄金交易基建,引领RWA金融新浪潮
  • Java 22 新特性及具体应用
  • week4-[字符数组]英语作文
  • Games101 作业1 旋转与投影
  • 量子链(Qtum)分布式治理协议
  • Qt+windows+QtInstallerFramework打包可执行文件教程-美观且简单
  • Django的Serializers与 fastapi 的Pydantic
  • Excel 转化成JSON
  • Java:LinkedList的使用
  • Django的Settings 配置文件详解
  • 【ArcGIS Pro 全攻略】GIS 数据格式终极指南:从原理到实战,再也不纠结选哪种格式!
  • React useState 全面深入解析
  • Linux 824 shell:expect
  • 基于5G NR NTN与DVB-S2X/RCS2的机载卫星通信终端性能分析
  • 低功耗模式DMA数据搬运问题解析
  • 在测试接入抖音小游戏订阅消息推送时遇到的问题
  • bun + vite7 的结合,孕育的 Robot Admin 【靓仔出道】(十八)