Java 堆内存溢出怎么处理
报 OutOfMemoryError: Java heap space 表示堆内存不足,可能是并发量增长需要更大堆,也可能是对象泄漏导致占用持续上升。正确顺序是取证优先:先用堆信息与垃圾回收统计确认堆使用与回收情况,再按容量调整堆上限并验证效果,最后通过堆快照分析对象来源定位泄漏。堆并非越大越好,过大会拉长回收停顿并挤压系统其它部分的内存。
基本信息
| 堆信息 | jcmd 的堆信息子命令查看使用量与上限 |
|---|---|
| 回收统计 | jstat 按间隔采样观察回收频率与各区占比 |
| 堆上限参数 | 启动时的最小与最大堆参数 |
| 快照参数 | 溢出时导出快照便于离线分析 |
| 容器场景 | 堆上限需小于容器内存上限 |
典型使用场景
- 服务报堆内存溢出后无法正常处理请求,需要快速恢复并取证
- 排查内存持续增长,判断是缓存设计问题还是对象泄漏
- 容器环境中进程被编排层杀掉,核对堆参数与容器上限的关系
- 性能调优前后对比回收频率与停顿,评估参数调整效果
- 上线前为应用规划合理的堆大小与快照输出配置
- 故障复盘时用快照分析定位占用最多的对象类型
取证与调整
取证与调整
jcmd <PID> GC.heap_info # 堆使用量与上限一览
jcmd <PID> GC.class_histogram | head -20 # 按类统计对象占用(会触发一次停顿)
jstat -gcutil <PID> 1000 5 # 每秒采样一次,观察各区占比与回收次数
jmap -dump:live,format=b,file=/data/dumps/heap.hprof <PID> # 导出堆快照(重)
# 推荐启动参数:溢出时自动留快照
# -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dumps
# 调整堆上限示例(留出系统与其它进程余量):
# java -Xms2g -Xmx2g -jar app.jar
# 容器场景:确认 Xmx 小于容器内存上限,避免被杀死
ls -lh /data/dumps/ # 确认快照文件已生成诊断项与含义
| 项 | 含义 | 判读要点 |
|---|---|---|
| 堆使用量 | 当前已用与上限 | 接近上限且回收后不下降需重点关注 |
| 回收频率 | 单位时间回收次数 | 频率升高说明压力持续增大 |
| 各区占比 | 新生代与老年代使用比例 | 老年代长期高位通常是泄漏信号 |
| 堆快照 | 对象与引用关系 | 用于定位占用最多的对象来源 |
| 容器上限 | 编排层给进程的内存上限 | 堆上限必须小于该值 |
堆上限不是越大越好:堆过大让回收停顿时间变长,并挤压页缓存与其他进程;容器里设置超过容器上限还会被编排层杀掉,表现像「莫名重启」。
导出堆快照会短暂影响服务性能,建议在低峰执行;同时配置溢出时自动导出的启动参数,故障瞬间的快照比重启后再补采更有价值。