news 2026/4/23 9:32:43

记一次线上OOM排查,JVM调优全过程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
记一次线上OOM排查,JVM调优全过程

周三下午,正在摸鱼,突然钉钉群里炸了:

[告警] 订单服务 POD重启 [告警] 订单服务 POD重启 [告警] 订单服务 POD重启

3个Pod连续重启,打开监控一看,内存直接打满然后被K8s杀掉了。

经典的OOM。

现象

  • 服务:订单服务(Java,Spring Boot)
  • 部署:K8s,3个Pod,每个限制4G内存
  • 现象:内存缓慢增长,到达4G后被OOM Kill
  • 频率:每隔2-3小时重启一次

第一反应:加内存?

领导说:内存不够就加嘛。

我:…加内存治标不治本,得找到根因。

排查过程

1. 先看GC日志

# JVM参数里加上GC日志-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/logs/gc.log

等了一个小时,服务挂了,捞出GC日志:

[Full GC (Allocation Failure) 3800M->3750M(4096M), 5.234 secs] [Full GC (Allocation Failure) 3780M->3760M(4096M), 5.567 secs] [Full GC (Allocation Failure) 3790M->3785M(4096M), 6.012 secs]

Full GC后内存几乎没释放,说明有内存泄漏,有东西一直占着不放。

2. dump内存

在容器里加了个脚本,OOM前自动dump:

# JVM参数-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/heap.hprof

但K8s的OOM Kill太快了,还没来得及dump就被杀了。

换个方式,手动dump:

# 找到Java进程PIDjps# 手动dump(等内存涨到3G左右时执行)jmap -dump:format=b,file=/logs/heap.hprof<pid>

dump出来一个3G的文件。

3. 分析heap dump

把文件拷到本地,用MAT(Memory Analyzer Tool)打开。

Leak Suspects Report: Problem Suspect 1: 256,789 instances of "com.xxx.OrderDTO" 占用内存:2.1 GB (54%)

25万个OrderDTO对象?这订单量也没这么大啊。

点进去看引用链:

java.util.concurrent.ConcurrentHashMap -> com.xxx.cache.LocalCache -> OrderDTO (256789 instances)

LocalCache,本地缓存。

4. 定位代码

// LocalCache.javapublicclassLocalCache{privatestaticfinalMap<String,OrderDTO>cache=newConcurrentHashMap<>();publicstaticvoidput(StringorderId,OrderDTOorder){cache.put(orderId,order);}publicstaticOrderDTOget(StringorderId){returncache.get(orderId);}// 没有remove方法// 没有过期机制// 没有大小限制}

经典错误:只往缓存里放,不清理。

一查代码提交记录,是3个月前一个同事为了"优化性能"加的,从那之后这个服务就开始间歇性OOM。

5. 修复

方案一:直接删掉这个缓存(最简单)

方案二:换成带过期的缓存

// 用Caffeine替代privatestaticfinalCache<String,OrderDTO>cache=Caffeine.newBuilder().maximumSize(10000)// 最多1万条.expireAfterWrite(5,TimeUnit.MINUTES)// 5分钟过期.build();publicstaticvoidput(StringorderId,OrderDTOorder){cache.put(orderId,order);}publicstaticOrderDTOget(StringorderId){returncache.getIfPresent(orderId);}

上线后,内存稳定在1.5G左右,再也没OOM过。

JVM参数调优

趁这个机会,把JVM参数也优化了一下。

之前的配置

-Xms2g -Xmx4g# 就这两个参数...

优化后的配置

# 堆内存-Xms4g -Xmx4g# 初始和最大一样,避免动态调整-XX:NewRatio=2# 年轻代:老年代 = 1:2# GC选择(JDK11+推荐G1)-XX:+UseG1GC -XX:MaxGCPauseMillis=200# 目标停顿时间200ms-XX:G1HeapRegionSize=8m# Region大小# 元空间-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m# GC日志-Xlog:gc*:file=/logs/gc.log:time,level,tags:filecount=5,filesize=100m# OOM时dump-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/# 容器感知(JDK8u191+)-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0# 使用容器内存的75%

监控指标

加了几个关键监控:

# Prometheus指标-jvm_memory_used_bytes-jvm_gc_pause_seconds_sum-jvm_gc_pause_seconds_count-jvm_classes_loaded_classes_total

设置告警:

  • 老年代使用率 > 80% 持续5分钟
  • Full GC 频率 > 1次/分钟
  • GC停顿时间 > 1秒

排查工具汇总

场景工具命令
查看堆内存jmapjmap -heap
dump内存jmapjmap -dump:format=b,file=heap.hprof
分析dumpMAT图形界面
实时监控jstatjstat -gcutil 1000
查看线程jstackjstack
在线分析Arthasdashboard/heapdump

Arthas神器

推荐用Arthas,在线诊断特别方便:

# 下载启动curl-O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar# 选择要attach的进程后:# 查看堆内存dashboard# 查看最占内存的对象heapdump --live /tmp/heap.hprof# 查看某个类的实例数sc -d com.xxx.OrderDTO vmtool --action getInstances --className com.xxx.OrderDTO --limit10# 查看方法调用watchcom.xxx.LocalCache put'{params, returnObj}'-x2

远程调试

这次OOM排查还好在公司,能直接连到服务器。

如果在家收到告警,K8s集群在公司内网,怎么办?

之前的方案是远程专线,但经常断,而且手机上操作kubectl很难受。

后来用星空组网把电脑和跳板机组到一起,在家也能kubectl进容器排查了。

总结

这次OOM排查的经验:

步骤工具/方法
1. 确认OOM监控告警、GC日志
2. dump内存jmap / HeapDumpOnOutOfMemoryError
3. 分析dumpMAT / jhat
4. 定位代码引用链分析
5. 修复上线代码修改
6. 加固监控JVM监控指标

常见的内存泄漏原因:

  • 缓存无限增长(本次)
  • 静态集合持续添加
  • 未关闭的连接/流
  • ThreadLocal使用不当
  • 监听器未注销

最后,写缓存的时候一定要想清楚:

  • 什么时候过期?
  • 最大存多少?
  • 怎么清理?

不然就等着半夜被电话叫醒吧。


有JVM相关问题欢迎评论区交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 2:40:59

RocketMQ如何保证高可用_详细实战

RocketMQ 高可用保障&#xff08;HA&#xff09;详细实战指南 这份文档讲的是“怎么让 RocketMQ 尽量不停 尽量不丢 出事能自动/快速恢复”。 高可用不是一个开关&#xff0c;是一整套工程&#xff1a;架构冗余 正确配置 客户端容错 运维监控 演练。 目录 1. 先把目标说…

作者头像 李华
网站建设 2026/4/23 5:04:22

电商客服压力山大?(Open-AutoGLM智能工单系统拯救日均万级售后请求)

第一章&#xff1a;电商客服压力山大&#xff1f;Open-AutoGLM破局之道在电商行业高速发展的今天&#xff0c;客服系统面临前所未有的挑战&#xff1a;咨询量激增、响应时效要求高、人力成本攀升。传统人工客服难以应对高峰时段的海量咨询&#xff0c;而基础聊天机器人又缺乏语…

作者头像 李华
网站建设 2026/4/1 2:13:17

Open-AutoGLM实战指南:5步搭建高效电商评价自动回复系统

第一章&#xff1a;Open-AutoGLM 电商评价自动回复在电商平台运营中&#xff0c;及时、准确地回应用户评价是提升客户满意度的关键环节。Open-AutoGLM 是一款基于开源大语言模型的自动化回复系统&#xff0c;专为处理电商用户评论设计&#xff0c;能够理解语义情感并生成个性化…

作者头像 李华
网站建设 2026/4/22 18:28:14

Open-AutoGLM安全升级指南,如何在2小时内完成MFA全流程集成

第一章&#xff1a;Open-AutoGLM安全升级指南概述随着大语言模型在自动化推理与代码生成场景中的广泛应用&#xff0c;Open-AutoGLM 作为开源智能代理框架&#xff0c;其安全性成为部署过程中的核心关注点。本指南旨在为系统管理员和开发人员提供一套完整的安全加固路径&#x…

作者头像 李华
网站建设 2026/4/16 20:16:47

日志泄露危机频发:Open-AutoGLM加密存储为何成最后防线?

第一章&#xff1a;日志泄露危机频发&#xff1a;安全防护的迫切需求近年来&#xff0c;随着企业数字化转型加速&#xff0c;系统日志成为运维与故障排查的重要依据。然而&#xff0c;日志数据中常包含用户身份信息、会话令牌、API密钥等敏感内容&#xff0c;一旦暴露&#xff…

作者头像 李华
网站建设 2026/4/19 4:30:27

17.5 安全保障机制:控制AI生成内容风险

17.5 安全保障机制:控制AI生成内容风险 在前几节中,我们探讨了模型工程化实施、Agent工作流构建、知识库设计和效果评估体系等关键技术环节。今天,我们将重点关注AI系统安全这一至关重要的主题——如何建立完善的安全保障机制,有效控制AI生成内容的风险,确保系统安全可靠…

作者头像 李华