线上 JVM 内存问题定位

问题

线上容器 JVM 频繁 OOM。先后有三个不同的现象

  1. 频繁FullGC

    1. 原因:同类型的对象数很多,没有被GC掉

    2. 解决:99线监控积累了很多guage数据,主要是请求处理慢,导致请求的guage数据堆积

  2. Major GC很慢

    1. 原因:有大对象,一直积攒

    2. 解决:mongo查询代码有坑,查询失败,导致查询的监控数据堆积在内存没有释放。监控使用k8s promethus请求监控,监控组件也有坑,没有超时释放监控数据。

  3. Minor GC很慢

    1. 原因:年轻代内存占用很多,朝生夕死的对象很多

    2. 解决:入参验证逻辑前置,无效的输入尽早排除,减少对象创建

定位步骤

  1. 查看gc日志

    • 从日志分析可能的内存泄露

    • 工具:https://gceasy.io/gc-index.jsp

    • 结论

      1. 堆内存没有清理

      2. 频繁FullGC

      3. 老年代内存持续上涨

  2. arthas分析实时内存

    • 工具:https://arthas.aliyun.com/doc/vmtool.html, 用memory命令查看内存

    • 结论:老年代内存一直没清理干净

  3. 内存dump

    • 工具:Java 线程&内存在线分析 说明文档 

    • 问题:用公司的在线内存分析工具, dump内存。但是内存数据大,有8G。手工从容器下载速度很慢而且影响线上服务。

    • 解决:dump出内存文件后,把容器摘流,使用在线分析工具,把内存文件上传到分析平台

    • 结论:能看出是哪个类型占用了内存,但是无法定位对象的引用链

  4. 内存分析

    • 工具:JProfiler

    • 问题:在线分析内容比较少,从分析平台上下载dump文件,加载到JProfiler分析

    • 结论

      1. 监控平台很多请求监控数据缓存在内存中,没有清理。根本原因是服务的请求QPS上涨到原来的3倍,且请求rt升高,导致很多请求的监控数据堆积在内从中

优化方案

  • 降低请求rt:优化mongo, redis读写速度

  • 关闭不必要的监控:95线,99线监控会占用很多内存。这些监控默认是打开的,修改配置关闭这些监控。

结果

  • 线上观察2周,未发现新的OOM问题。内存回收正常,水位较低。

  • FullGC 优化结束后,虽然水位降低,但是请求量大的时候,内存依然比较紧张,且GC耗时严重,继续进行major/min GC耗时优化。

  • 完成major/minGC耗时优化后,GC年轻代内存分配从原先的400M/s下降到60M/s, minor GC 从秒级下降到ms级, 次数从15次+降到2次. 年轻代占用从1G下降到300M;major GC耗时从秒级下降到ms级,总内存占用从50%+下降到个位数。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值