前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次OOM引发的线上事故

记一次OOM引发的线上事故

作者头像
灬沙师弟
发布2023-10-25 11:45:17
2180
发布2023-10-25 11:45:17
举报
文章被收录于专栏:Java面试教程Java面试教程

背景

最近线上服务平均两周就会出现重启的现象,同时SRE的同事发现重启前服务占用内存非常高,重启后内存下降,可见该服务是逐步耗尽系统内存。给力的SRE同事最后发现是服务所用的框架导致的内存被撑爆了。本文在本地模拟在这次线上问题,并记录这次问题的排查过程

本地模拟

首先由于线上服务间隔两周才出现重启的情况,为了在本地模拟线上Metaspace OOM的情况, 采用JMeter对本地服务进行压测。本地的操作系统是Mac OS。使用top 命令查看压测之前的程序的内存占用情况,如下图所示

可以看到程序整体占用2495M。然后用JMeter对服务进行压测。在压测的过程中在终端使用反复使用jcmd [PID] GC.heap_info命令, 重点观察Metaspace 区域数据变化

可以看到Metaspace中committed在飙升

排查与解决

使用jmap -dump:format=b,file=[filename].bin [PID]命令分别在压测刚开始和结束之前打印堆快照。然后使用MAT工具对快照进行分析。下面第一张图片一开始的快照, 第二张是压测之后的快照。

对比上面两张图可以明显看到,压测一段时间后Class的数量与Class loader的数量有了显著的上升。我们知道Java 8使用Metaspace来存贮类的元数据以及类加载器,Metaspace占用的是本地堆内存(native heap),所以Metaspace的增长导致了本地内存“撑爆”了。

可以通过-XX:MaxMetaspaceSize来设置触发Metaspace回收的阈值, 保证Metaspace不会太大,超过阈值就FullGC。但是这治标不治本,为什么会有这么多类加载器呢?

TranletClassLoader并不是业务层自定义的ClassLoader, 深入到框架层面的代码发现有如下代码。

每次请求都会调用template.newTransformer(), 该方法每次都会生成一个TransletClassLoader 去加载类TemplatesImpl,慢慢导致Metaspace不断增长。询问同事知道,这个API是框架层面暴露给监控部门调用,获取服务的健康状态, 请求量不是很大,所以才会有两个礼拜内存才满的现象。

找到问题的原因之后,目前先给线上服务加上-XX:MaxMetaspaceSize参数,框架部门的同事开始着手处理代码问题。

总结

Java 8开始彻底移除PermGen, 引入Metaspace来解决java.lang.OutOfMemoryError: PermGen。但是不代表对Metaspace可以不管不问了,使用不当Metaspace会导致本地内存溢出的情况。也有JVM大神就觉得Metaspace取代perm的好处不是那么明显,有点费力不讨好的感觉。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java面试教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 本地模拟
  • 排查与解决
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档