一次内存溢出事故 - 用 jprofiler 分析 gc root

事情经过

事情是这样,公司项目是一个springcloud的微服务,服务每隔半个月就会发生一次频繁的fullGC。后来定位到是缓存不合理导致的,该缓存的key是一条条sql,value是表名。这个缓存是用来干嘛呢?查了下他主要是分库组件sharding-jdbc在执行sql时,首先要通过这个缓存来获取sql对应的表。这个缓存设计的大小是1000,超时时间1天,而且用的一个LocalCache是强引用。因为在我们的生产环境中经常会有一下批量插入查询的操作,一个插入一千条数据的sql放在这个地方,就可能是一个 2.5MB左右的字符串。也就说极端情况,如果有几百条这种大sql被缓存进来,那么一下子就会占用1G的内存,而我们的应用堆大小只有5个GB,所以悲剧时不时就发生了。后来发了个邮件给架构组同事,修改了这部分代码,把sql变成sql的hashCode,问题就解决了。

jprofiler 使用过程

分析出来后原因是挺简单的,这里记录一下用到的工具jprofiler,如何用jprofiler分析GCRoot。首先用jmap获取java进程的dump文件,命令如下:

	jmap -dump:live,format=b,file=dump.hprof 5092

然后,用jprofiler导入dump文件,按照下图顺序点击,在弹出的窗口选择上面用jmap生成的文件即可。
在这里插入图片描述
导入后的界面长这样:
在这里插入图片描述
接下来,点击某一类型的对象,选择 incoming reference 进入:
在这里插入图片描述
进入后即可看到一个个的对象如下图所示,点击上方的size,将对象按大小排序后即可重点分析大对象。点击对应的对象,再点击 show paths to GC 即可看到一级一级的引用关系。以我选中的这个对象为例,看样子是一些jar包路径,查看gcroot,显示是由System类中的静态变量 props 持有。
在这里插入图片描述

总结

在整个分析溢出异常的过程中,基本的思路是有的:

1.保存异常现场(jmap获取dump文件),生产环境中如果由多个微服务部署,可以直接dump,否则的话还是要先重启,保证生产,再想办法再测试环境复现问题。
2.jprofiler分析大对象的持有者。
3.结合代码进行优化。

在分析过程中,我更多的时间反而是花在了工具学习上,期间尝试过Jvisualvm(java自带的),发现不太好用。后来换成了jprofiler。
最后发现原因后,成就感是满满的,感觉自己不光是在CRUD了~~

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值