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

JVM——OOM异常

目录

OOM异常***

你听过直接内存吗?

什么是 OOM

常见 OOM 类型及产生原因

OOM 触发完整场景

OOM 问题定位步骤

OOM 解决与优化方案


OOM异常***

你听过直接内存吗?

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致 OutOfMemoryError 异常出现。

简记:

直接内存又称堆外内存,是虚拟机内存之外的内存,直接内存不会进行垃圾回收,当我们使用的时候要手动进行回收,不然就会导致内存泄漏。

什么是 OOM

全称java.lang.OutOfMemoryError,简称OOM,意为「内存溢出」;

本质:JVM 无法申请到足够内存来存放新对象 / 数据,抛出的致命错误;

范围:不只是「堆溢出」,还包括方法区溢出、直接内存溢出等多种类型。

常见 OOM 类型及产生原因

1. 堆溢出(最常见)

  • 错误信息java.lang.OutOfMemoryError: Java heap space

  • 核心原因

    1. 老年代满了:执行 Full GC 后仍无法容纳新对象 / 晋升对象;

    2. 大对象分配失败:超大对象无法放入 Eden 区,也无法放入老年代;

    3. 整体堆内存耗尽:新生代 + 老年代总内存达到-Xmx上限,无法再扩容;

    4. 内存泄漏:大量对象被长期引用(如缓存未清理、静态集合无限增长),无法被 GC 回收。

2. 方法区溢出

  • 错误信息:

    • JDK7 及之前:java.lang.OutOfMemoryError: PermGen space

    • JDK8 及之后:java.lang.OutOfMemoryError: Meta space

  • 核心原因

    方法区(永久代 / 元空间)被类元数据占满,典型场景:

    • 加载大量第三方 Jar 包(如 Tomcat 部署过多应用);

    • 框架动态生成大量类(如 MyBatis Mapper、AOP 代理、Feign 接口、CGLIB 动态子类);

    • 大量动态反射生成类,导致类加载器无法卸载,元数据持续累积。

3. 直接内存溢出

  • 错误信息java.lang.OutOfMemoryError: Direct Memory space

  • 核心原因:NIO 等框架使用的直接内存(Direct ByteBuffer)超过-XX:MaxDirectMemorySize限制,未被及时释放。

OOM 触发完整场景

触发阶段OOM 类型核心原因
Minor GC 阶段Java heap space1. Minor GC 前老年代空间担保失败,Full GC 后仍无足够空间;2. 新生代 + 老年代整体内存耗尽,无法分配新对象
Full GC 阶段Java heap spaceFull GC 后堆内存仍无法容纳新对象
方法区阶段PermGen/Meta space方法区被类元数据占满,Full GC 无法释放足够空间
直接内存阶段Direct Memory space直接内存使用超过上限,未及时释放

OOM 问题定位步骤

第一步:生成堆转储文件(Heap Dump)

在 JVM 启动参数中添加:

-Xms30m -Xmx30m -XX:+HeapDumpOnOutOfMemoryError
  • 作用:OOM 发生时自动生成.hprof堆快照文件,记录当时内存状态;

  • -Xms/-Xmx:设置堆大小(便于复现问题);

  • -XX:+HeapDumpOnOutOfMemoryError:触发 OOM 时生成 dump 文件。

第二步:分析堆转储文件

使用工具打开.hprof文件:

  • IDEA 直接打开;

  • JDK 自带工具:jhatjvisualvm

  • 专业工具:Eclipse MAT、YourKit、VisualVM 等。

第三步:定位问题根源

  1. 收集错误信息:查看日志,确认 OOM 类型(堆 / 方法区 / 直接内存);

  2. 分析堆快照:

    • 查看内存占用最高的对象 / 数据结构;

    • 检查是否存在内存泄漏:长时间存活的对象、未清理的缓存、静态集合无限增长;

    • 确认是否存在大对象(如超大数组、集合);

  3. 检查内存使用趋势:是否存在持续的内存增长,未被 GC 回收;

  4. 定位代码位置:找到创建大量对象 / 动态类的业务代码或框架配置。

OOM 解决与优化方案

1. 堆溢出优化

  • 增加堆内存:调大-Xmx参数(治标,需配合代码优化);

  • 修复内存泄漏

    • 清理无用对象引用(如手动清空集合、关闭资源);

    • 合理设计缓存(设置过期时间、限制缓存大小);

    • 避免静态集合无限存储对象;

  • 减少大对象:拆分超大数组 / 集合,避免一次性加载全量数据;

  • 优化对象创建:复用对象(如对象池),减少频繁创建 / 销毁。

2. 方法区溢出优化

  • 增加元空间内存:JDK8+ 调大-XX:MaxMetaspaceSize

  • 减少动态类生成

    • 避免过度使用动态代理(如 AOP、MyBatis Mapper);

    • 优化框架配置,限制动态类数量;

    • 及时卸载无用类(确保类加载器可被 GC 回收);

  • 精简依赖:移除不必要的第三方 Jar 包,减少类加载数量。

3. 直接内存溢出优化

  • 限制直接内存大小:设置-XX:MaxDirectMemorySize

  • 及时释放直接内存:手动调用DirectBuffer.cleaner().clean()释放;

  • 避免过度使用 NIO 直接缓冲区,改用堆内缓冲区。

4. 通用优化

  • 监控与预警:使用 JMX、Prometheus 等工具监控内存使用趋势;

  • 性能测试:压测场景下验证内存稳定性,提前发现问题;

  • 代码规范:避免无限增长的集合、长生命周期的局部变量、未关闭的资源。

http://www.jsqmd.com/news/589393/

相关文章:

  • EdgeRemover:Windows系统下Microsoft Edge浏览器的彻底卸载方案与实现原理
  • Spring Boot项目实战:用Coze官方Java SDK实现JWT鉴权与工作流调用(含完整代码)
  • OpenClaw技能扩展指南:千问3.5-27B驱动公众号自动发布
  • QNX Shell指令大全:从pidin到slog2info的实战指南(附常用命令速查表)
  • 从零到一:手把手教你部署Pikachu靶场实战环境
  • 科技行业裁员潮:现状、案例与应对策略
  • ADS重新安装失败排查指南:从注册表清理到环境变量配置
  • 无代码自动化:OpenClaw+Qwen3-14B可视化任务编排器使用
  • 探索Greasy Fork:解锁浏览器潜能的开源工具平台
  • Swagger弹窗报错终极排查指南:从拦截器到全局处理的深度解析
  • LPDDR5读训练实战:手把手教你用示波器抓取tWCK2DQO和tDQSQ时序(附JESD209-5B解读)
  • TexturePacker打出的图集,如何在Unity里自动设置Android/iOS平台格式?一个脚本搞定
  • 从Level2实时数据到情绪周期:用免费API搭建你的第一个量化监控面板
  • Cursor 与 Copilot:从架构到实战,AI编程助手的核心差异与选型指南
  • 光影规划师 | 巧用 SunCalc.org 数据科学预判“黄金时刻”与“建筑投影”-每天一个提升出片率的地理工具(3/10)
  • 如何用AI传承千年中医智慧:仲景中医大语言模型完整指南
  • 无代码开发:用自然语言控制OpenClaw+Qwen3.5-9B处理Excel
  • uniapp顶部导航栏适配方案:利用CSS变量与navigationStyle优化
  • 高速电路设计中的时钟偏移(Skew)与时钟抖动(Jitter):原理、影响与优化策略
  • 如何实施企业SEO网站推广
  • ColorControl终极指南:专业级NVIDIA显卡与LG电视显示调校完全手册
  • 告别复制粘贴!用iFlow CLI+Claude Code,让AI真正理解你的Java老项目
  • ComfyUI-Easy-Use中Flux采样器Guidance参数的深度技术解析与优化实践
  • 深入解析LPDDR4 Write Leveling:从Fly-by拓扑到时序校准的实战指南
  • ThinkPHP6项目实战:手把手教你搞定微信小程序支付(含证书配置与签名避坑)
  • Veeam Backup 13 实战指南:通过UI界面高效备份VMware ESXi虚拟机
  • 学习mysql第一天
  • OpenClaw学术助手搭建:gemma-3-12b-it自动生成论文阅读报告
  • 别让雷达变‘瞎子’:手把手教你用Ti/加特兰芯片搞定车载毫米波雷达干扰(附代码思路)
  • 别再搞混了!Vue3里xgplayer播放FLV视频与FLV直播流,配置到底差在哪?