线上JVM OOM问题,如何排查和解决?
今天咱们来聊聊让无数 Java 开发者头疼的 JVM OOM(Out Of Memory,内存溢出)问题。在面试中,OOM 问题也是面试官的“心头好”,因为它能直接考察你对 JVM 的理解,以及你在实际问题面前的排查和解决能力。
一、JVM OOM 到底是什么?
简单来说,JVM OOM 就是 Java 虚拟机的内存用完了,而且垃圾回收器(GC)也无能为力,没办法再为新对象分配内存,于是抛出了 java.lang.OutOfMemoryError 错误。这就好比你开着一辆车,油箱里的油已经耗尽,但你还想继续加速,结果只能是熄火。
二、OOM 为啥会发生?
OOM 的原因多种多样,但归根结底就两个字——“不够用”。具体来说,有这么几种常见情况:
- 内存分配不足:JVM 初始化时,堆内存、永久代(或元空间)等区域分配得太小,根本不够业务跑。比如,你的应用要处理海量数据,但堆内存只给了 128MB,这不就是“杯水车薪”嘛。
- 大对象申请:一次性申请的内存太大,超出了 JVM 的承受范围。比如,你试图一次性加载一个几 GB 的文件到内存中,JVM 根本就装不下。
- 内存泄漏:程序中某些地方申请了内存,但因为代码逻辑错误,这些内存永远不会被释放,就像一个无底洞,不断吞噬着 JVM 的内存。
- 代码问题:程序里某些对象被频繁创建,用完后却没有被及时释放,导致内存被一点点蚕食。比如,一个定时任务不断往缓存里塞数据,但从来没清理过,时间一长,内存就被塞满了。
三、OOM 都有哪些“变种”?
1. Java 堆内存溢出
这是 OOM 最常见的形式,错误信息是 java.lang.OutOfMemoryError: Java heap space。堆内存是 JVM 里存放对象实例的地方,如果堆内存满了,垃圾回收器又没办法清理出足够的空间,就会触发这个错误。
2. 永久代/元空间溢出
在 JDK 7 及以下版本里,有永久代(PermGen),用于存放类的元数据、常量池等信息。如果应用加载了大量类(比如使用了动态代理、字节码操作等技术),永久代很容易被撑爆,抛出 java.lang.OutOfMemoryError: PermGen space 错误。从 JDK 8 开始,永久代被元空间(Metaspace)取代,但原理类似,错误信息也变成了 java.lang.OutOfMemoryError: Metaspace。
3. 栈内存溢出
栈内存是线程私有的,用于存放方法调用的局部变量、操作栈等信息。如果一个方法调用链太深(比如递归调用过深),或者方法里局部变量太多,栈内存就会溢出,抛出 java.lang.StackOverflowError。注意,虽然名字里有“Overflow”,但它本质上也是 OOM 的一种。
4. 直接内存溢出
直接内存是 JVM 外的一块内存,通常用于 NIO 操作。如果程序中大量使用 NIO,且没有正确管理直接内存,就会导致直接内存溢出,抛出 java.lang.OutOfMemoryError: Direct buffer memory 错误。
四、排查 OOM 的“杀手锏”
当线上服务出现 OOM 时,别慌,我们有这些“杀手锏”:
1. 启用 JVM 诊断选项
在启动应用时,加上这些参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump
-Xlog:gc* (JVM 9 及以上)
-XX:+PrintGCDetails -Xloggc:/path/to/gc.log (JVM 8 及以下)
这些参数可以让 JVM 在 OOM 时生成内存堆转储文件和 GC 日志,帮助我们分析问题。
2. 分析错误日志
仔细查看应用日志和 OOM 错误堆栈信息,看看是哪个内存区域出了问题。
3. 分析堆转储文件
用 JVisualVM、Eclipse MAT、JProfiler 这些工具打开堆转储文件,找出内存占用大户,看看是不是有内存泄漏。
4. 检查 GC 日志
分析 GC 日志,看看垃圾回收的频率、暂停时间和各内存区的使用情况,判断是不是垃圾回收出了问题。
5. 代码审查和优化
从代码层面找原因,看看是不是有缓存没清理、静态集合不断增长等内存泄漏问题。发现问题后,优化代码,减少对象创建,及时释放内存。
五、解决 OOM 的“锦囊妙计”
1. 增加内存
- 堆内存:用
-Xmx参数增加最大堆内存,比如-Xmx2g。 - 永久代/元空间:用
-XX:MaxPermSize(JDK 7 及以下)或-XX:MaxMetaspaceSize(JDK 8 及以上)增加大小。 - 直接内存:用
-XX:MaxDirectMemorySize参数增加直接内存大小。
2. 优化代码
- 释放对象:确保用完的对象能被垃圾回收,比如把不用的缓存清掉。
- 避免大对象:能不用大对象就不用,实在要用,也尽量拆分成小块。
- 用弱引用/软引用:比如缓存可以用
WeakHashMap或SoftReference,避免内存泄漏。
3. 调优垃圾回收器
根据应用的特点,选择合适的 GC 算法(比如 G1、CMS),并调整参数,比如 -XX:+UseG1GC -XX:MaxGCPauseMillis=200。
4. 管理外部资源
确保文件句柄、数据库连接等外部资源用完后能正确关闭,别让它们占着内存不放。
5. 持续监控和预警
用 JMX、Prometheus、Grafana 等工具实时监控 JVM 内存使用情况,一旦发现异常,立刻报警,提前解决问题。
六、实战案例分析
案例一:大数据量处理导致堆内存不足
症状:应用处理大数据量时,抛出 java.lang.OutOfMemoryError: Java heap space。
排查:
- 启用 GC 日志和堆转储选项。
- 分析 GC 日志,发现 Full GC 频繁,但内存还是不够用。
- 用 JVisualVM 分析堆转储文件,发现大量大对象占用了内存。
解决:
- 优化算法,减少内存占用。
- 通过
-Xmx增加堆内存。 - 改进数据处理流程,比如用流式处理,减少内存峰值。
案例二:动态类生成导致元空间不足
症状:动态生成类时,抛出 java.lang.OutOfMemoryError: Metaspace。
排查:
- 启用堆转储和 GC 日志选项。
- 分析 GC 日志,发现元空间增长飞快,类加载频繁。
- 用工具查看元空间内容,发现大量动态生成的类没被卸载。
解决:
- 通过
-XX:MaxMetaspaceSize增加元空间大小。 - 优化动态类生成逻辑,减少不必要的类加载。
案例三:递归调用过深导致栈内存不足
症状:递归调用抛出 java.lang.StackOverflowError。
排查:分析错误堆栈,发现递归调用深度太大。
解决:
- 改用迭代算法替代递归。
- 优化算法,减少递归深度。
七、总结
JVM OOM 是一个复杂但常见的问题,它可能出现在堆内存、永久代/元空间、栈内存或直接内存等区域。排查 OOM 的关键在于启用诊断选项(如堆转储和 GC 日志)、分析错误日志和堆转储文件、检查垃圾回收日志。解决 OOM 的方法包括增加内存、优化代码、调优垃圾回收器参数和管理外部资源。持续监控和预警机制可以有效预防 OOM 问题的发生。
希望这篇文章能帮助你在面试中更好地回答 OOM 相关问题,也能在实际工作中解决类似问题。如果你在工作中也遇到过 OOM 问题,欢迎在评论区留言,我们一起交流经验。
最后再分享一道常见的后端面试题。
说说main方法的执行过程?
示例代码:
public class Application {public static void main(String[] args) {Person p = new Person("大彬");p.getName();}
}class Person {public String name;public Person(String name) {this.name = name;}public String getName() {return this.name;}
}
执行main方法的过程如下:
- 编译
Application.java后得到Application.class后,执行这个class文件,系统会启动一个JVM进程,从类路径中找到一个名为Application.class的二进制文件,将Application类信息加载到运行时数据区的方法区内,这个过程叫做类的加载。 - JVM 找到
Application的主程序入口,执行main方法。 main方法的第一条语句为Person p = new Person("大彬"),就是让 JVM 创建一个Person对象,但是这个时候方法区中是没有Person类的信息的,所以 JVM 马上加载Person类,把Person类的信息放到方法区中。- 加载完
Person类后,JVM 在堆中分配内存给Person对象,然后调用构造函数初始化Person对象,这个Person对象持有指向方法区中的 Person 类的类型信息的引用。 - 执行
p.getName()时,JVM 根据 p 的引用找到 p 所指向的对象,然后根据此对象持有的引用定位到方法区中Person类的类型信息的方法表,获得getName()的字节码地址。 - 执行
getName()方法。
最后分享一份大彬精心整理的大厂面试手册,包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等高频面试题,非常实用,有小伙伴靠着这份手册拿过字节offer~


需要的小伙伴可以自行下载:
http://mp.weixin.qq.com/s?__biz=Mzg2OTY1NzY0MQ==&mid=2247485445&idx=1&sn=1c6e224b9bb3da457f5ee03894493dbc&chksm=ce98f543f9ef7c55325e3bf336607a370935a6c78dbb68cf86e59f5d68f4c51d175365a189f8#rd
围观朋友⭕:dabinjava
相关文章:
线上JVM OOM问题,如何排查和解决?
今天咱们来聊聊让无数 Java 开发者头疼的 JVM OOM(Out Of Memory,内存溢出)问题。在面试中,OOM 问题也是面试官的“心头好”,因为它能直接考察你对 JVM 的理解,以及你在实际问题面前的排查和解决能力。 一…...
Linux的缓存I/O和无缓存IO
一、I/O缓存的背景 I/O缓存是指在内存里开辟一块区域,存放用来接收用户输入和用于计算机输出的数据,以减小系统开销和提高外设效率。linux对IO文件的操作分为不带缓存的IO操作和带缓存的IO操作(标准IO操作)。为什么存在C标准I/O库…...
【弹性计算】弹性裸金属服务器和神龙虚拟化(三):弹性裸金属技术
弹性裸金属服务器和神龙虚拟化(三):弹性裸金属技术 1.弹性裸金属技术背景1.1 传统 KVM 虚拟化系统导致 CPU 计算特性损失1.2 传统 KVM 虚拟化系统导致资源争抢不可避免1.3 传统 KVM 虚拟化系统导致 I/O 性能瓶颈 2.弹性裸金属技术实现2.1 VPC…...
【MySQL】(2) 库的操作
SQL 关键字,大小写不敏感。 一、查询数据库 show databases; 注意加分号,才算一句结束。 二、创建数据库 {} 表示必选项,[] 表示可选项,| 表示任选其一。 示例:建议加上 if not exists 选项。 三、字符集编码和排序…...
Hyper-V -docker-vmware 三者的关系
1. Docker 正常运行,需要启动Hyper-V ,打开 hypervisorlaunchtype 2.VMware 正常时,需要关闭Hyper-V ,关闭 hypervisorlaunchtype 2.1资源管理器->CPU 里要开启虚拟化 2.2 服务-停掉HV服务 2.3 控制面板 不勾选 2.4 …...
IP-----双重发布
目录 6.双重发布 1.重发布的作用 2.部署条件 1.必须存在ASBR 2.种子度量值 3.重发布的规则 4.重发布的数量 5.重发布的场景 1.场景和规则 2.直连和静态 3.动态RIP 4.动态OSPF 5.更改开销值 6.重发布的问题1 7.重发布的问题2 1.流量 2.前缀列表 3.偏移列表 4…...
【新立电子】探索AI眼镜背后的黑科技,FPC如何赋能实时翻译与语音识别,点击了解未来沟通的新方式!
在全球化的今天,语言障碍成为人们沟通与交流的一大难题。AI眼镜作为一种新兴的智能设备,正在通过实时翻译与语音识别功能,打破语言壁垒,为人们提供无缝沟通的解决方案。FPC在AI眼镜中的应用,为实时翻译与语音识别功能的…...
LeetCode 热题 100_寻找两个正序数组的中位数(68_4_困难_C++)(二分查找)(先合并再挑选中位数;划分数组(二分查找))
LeetCode 热题 100_寻找两个正序数组的中位数(68_4) 题目描述:输入输出样例:题解:解题思路:思路一(先合并再挑选中位数):思路二(划分数组(二分查找…...
Java多线程与高并发专题——深入ReentrantReadWriteLock
深入ReentrantReadWriteLock 读写锁出现原因 synchronized和ReentrantLock都是互斥锁。如果说有一个操作是读多写少的,还要保证线程安全的话。如果采用上述的两种互斥锁,效率方面很定是很低的。在这种情况下,咱们就可以使用ReentrantReadWr…...
【Python 语法】算法合集
查找二分查找代码大 O 表示法 广度优先搜索代码 狄克斯特拉算法 递归递归调用栈 分而治之(divide and conquer,D&C)贪心教室调度问题背包问题集合覆盖问题 动态规划背包问题旅游行程最优化 遇到问题时, 如果不确定该如何 高效…...
[STM32]从零开始的STM32 BSRR、BRR、ODR寄存器讲解
一、前言 学习STM32一阵子以后,相信大家对STM32 GPIO的控制也有一定的了解了。之前在STM32 LED的教程中也教了大家如何使用寄存器以及库函数控制STM32的引脚从而点亮一个LED,之前的寄存器只是作为一个引入,并没有深层次的讲解,在教…...
C++ ++++++++++
初始C 注释 变量 常量 关键字 标识符命名规则 数据类型 C规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存 整型 sizeof关键字 浮点型(实型) 有效位数保留七位,带小数点。 这个是保…...
C# 牵手DeepSeek:打造本地AI超能力
一、引言 在人工智能飞速发展的当下,大语言模型如 DeepSeek 正掀起新一轮的技术变革浪潮,为自然语言处理领域带来了诸多创新应用。随着数据隐私和安全意识的提升,以及对模型部署灵活性的追求,本地部署 DeepSeek 成为众多开发者和…...
phpstudy安装教程dvwa靶场搭建教程
GitHub - digininja/DVWA: Damn Vulnerable Web Application (DVWA) Dvwa下载地址 Windows版phpstudy下载 - 小皮面板(phpstudy) 小皮下载地址 1选择windows 版本,点击立即下载 下载完成,进行解压,注意不要有中文路径 点击.exe文件进行安装…...
最新版本SpringAI接入DeepSeek大模型,并集成Mybatis
当时集成这个环境依赖冲突,搞了好久,分享一下依赖配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…...
FastAPI 学习笔记
简介: FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 并基于标准的 Python 类型提示。 关键特性: 快速:可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic&…...
Elasticsearch:过滤 HNSW 搜索,快速模式
作者:来自 Elastic Benjamin Trent 通过我们的 ACORN-1 算法实现,探索我们对 Apache Lucene 中的 HNSW 向量搜索所做的改进。 多年来,Apache Lucene 和 Elasticsearch 一直支持使用 kNN 查询的过滤搜索,允许用户检索符合指定元数据…...
华为hcia——Datacom实验指南——STP工作基本原理及STP/RSTP基本功能配置
什么时候需要用到STP 在二层交换网络中,为了避免环路产生。 什么是STP STP生成树协议,是用来在冗余链路上消除二层环路。在众多交换机中,需要设置出一个根桥,其余的交换机称为非根桥,根桥是整个交换网络的核心&…...
Vue核心知识:动态路由实现完整方案
在Vue中实现动态路由,并结合后端接口和数据库表设计,是一个复杂的项目,需要多个技术栈和步骤的配合。以下将详细描述整个实现过程,包括数据库设计、后端接口设计、前端路由配置以及如何实现动态路由的功能。 目录 一、需求分析二…...
【Maui】系统找不到指定的文件Xamarin.Android.Aapt2.targets
文章目录 前言一、问题描述二、解决方案三、软件开发(源码)四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI,可从单个共享代码库开发可在 And…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
