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

堆与 GC 入门:对象怎么分配?为什么会 OOM?怎么排查?

你在业务里最常见的 JVM 异常之一:

  • OutOfMemoryError: Java heap space

但“堆”不是一个黑盒,它至少有三件事你必须搞懂:

  • 对象怎么进堆、怎么活下来
  • GC 为什么要分代
  • OOM 到底是“大对象瞬间打爆”还是“泄露慢慢涨”

1. 堆是什么:几乎所有对象的出生地

在 HotSpot 里,绝大多数对象分配在堆上。

例外你可以先忽略(逃逸分析/标量替换之类优化),先把主线抓住:

  • 对象创建 -> 堆上分配 -> 引用在栈里传来传去 -> 垃圾回收器回收不可达对象

2. 为什么要分代:大部分对象“活不久”

GC 分代的经验规律:

  • 绝大多数对象朝生夕死(请求对象、临时集合、DTO 等)

因此把堆分成:

  • 新生代:专门收短命对象(回收频繁但成本低)
  • 老年代:长期存活对象(回收不频繁但一次成本高)

你只要理解这个策略,就能解释很多 GC 现象。


3. 一次对象分配的典型旅程(主线版)

  • 对象优先在新生代分配
  • Minor GC:回收新生代
  • 多次 Minor GC 后仍存活的对象,会晋升到老年代
  • 老年代压力大时触发 Major/Full GC(具体与收集器实现相关)

4. 两类 OOM:你要先分清

4.1 瞬时型:大对象/突发流量把堆打爆

现象:

  • 业务突发流量
  • 堆瞬间被顶满
  • Full GC 也回收不下来

4.2 渐进型:内存泄露

现象:

  • 堆使用率慢慢爬
  • Full GC 后仍然回不到低位
  • 最终 OOM

5. 实战:一个最小排障闭环(建议你背下来)

5.1 第一步:确认堆配置与实时占用

  • 看启动参数:jcmd <pid> VM.command_line
  • 看堆信息:jcmd <pid> GC.heap_info

5.2 第二步:看对象直方图(快速抓“大户”)

  • jcmd <pid> GC.class_histogram

你关注:

  • 哪些类实例数/总大小异常
  • 是否出现你业务里不该无限增长的缓存对象

5.3 第三步:必要时堆转储做根因定位

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

然后用:

  • Eclipse MAT / IDEA Profiler 分析

重点找:

  • Dominator Tree
  • GC Roots 到可疑对象的引用链

6. 常见导致泄露的“写法模式”

你不需要记所有工具,先记常见坑:

  • 静态集合缓存不淘汰
  • ThreadLocal使用不当(没 remove)
  • 监听器/回调注册不注销
  • 大对象缓存(如大字符串、byte[])

7. JDK 1.7 与 JDK 1.8:你至少要知道的差异点

这篇主要讲堆,但你要知道一个经常混淆的点:

  • JDK 1.7:类元数据在PermGen
  • JDK 1.8:类元数据在Metaspace

所以:

  • 看到PermGen space/Metaspace不要误判成堆 OOM

8. 总结

  • 堆是对象主要分配区,GC 主战场
  • 分代是为了高效回收短命对象
  • OOM 先分清:突发型 vs 泄露型
  • 排障最小闭环:heap_info -> class_histogram -> dump + MAT
http://www.jsqmd.com/news/503256/

相关文章:

  • ANSYS APDL命令流实战:从矩形绘制到布尔操作的5个高效技巧
  • 手把手重构你的评估流水线:用Dify替代人工标注——3天上线、误差率↓68%、ROI 23.7倍的实战路径
  • 简化版麦克风阵列实战:ODAS与ODAS_Web在树莓派上的部署与优化
  • GanttProject完全指南:开源项目管理工具的深度应用与实践
  • uniapp uni-forms动态表单校验:解决v-if条件渲染导致的字段绑定失效问题
  • Linux 的 chroot 命令
  • Fire Dynamics Simulator (FDS) 技术白皮书:从核心功能到实践应用
  • ER-Save-Editor:从零开始掌握艾尔登法环存档编辑的艺术
  • springboot写真摄影旅拍预约管理系统
  • JVM 堆参数怎么设:先建立内存基线,再谈性能优化
  • 【WebRTC】深入解析getStats():从数据采集到渲染的全链路监控
  • Qwen3-TTS声音克隆案例展示:3秒复制人声,多语种合成效果超自然
  • MachOView二进制分析工具:macOS开发者必备的Mach-O文件解析神器
  • HeapDump + MAT:从一次 OOM 到根因定位的完整链路
  • DeepChat跨平台部署实战手册:从零构建你的AI智能助手
  • 存算一体芯片驱动开发必读:用8个结构体+12个宏定义,实现跨工艺节点(7nm→3nm)指令集无感迁移
  • 实战指南:如何用UNICORN实时检测APT攻击(附配置避坑技巧)
  • 如何快速构建戴森球计划高效工厂:FactoryBluePrints蓝图库完全指南
  • Flutter vs Uniapp:2024年移动端跨平台开发框架实战对比(附避坑指南)
  • HY-Motion 1.0应用解析:如何将生成的动作无缝接入Unity/Unreal?
  • 三角函数正交性的数学本质与工程应用解析
  • UDS诊断实战:深入解析2E服务的数据写入机制与应用场景
  • 关于110kV变电站电气一次部分设计与选型的详细说明书及CAD绘制规范参考手册
  • AntV L7地图交互进阶:如何优雅地实现Popup信息框与鼠标事件
  • Linux 的 cksum 命令
  • lite-avatar形象库效果展示:150+高质量数字人形象真实案例分享
  • 深入SPDK vhost-blk内部:从IO请求到完成的完整生命周期解析
  • 如何高效使用Open Interpreter:5个实战场景提升开发效率
  • 圣女司幼幽-造相Z-Turbo性能实测:单次生成耗时<8秒,A10显卡吞吐达3.2 img/s
  • 如何快速掌握STM32嵌入式控制:面向新手的完整实战指南