侧边栏壁纸
博主头像
丛庆

没事儿写代码,有事写代码。email:1024@cong.zone

  • 累计撰写 116 篇文章
  • 累计创建 97 个标签
  • 累计收到 4 条评论

【Java】记一次jvm内存泄漏的排查

丛庆
2022-04-28 / 0 评论 / 0 点赞 / 766 阅读 / 1,156 字 / 正在检测是否收录...
温馨提示:
部分资料和图片来源于网络,如有危害到您的利益请与我联系删除,1024@cong.zone。

生产上某个服务一直无响应,频繁出现了FullGC。记录一下排查过程

确认jvm泄露

现象,某个接口长时间无响应,日志输出

java.lang.OutOfMemoryError: GC overhead limit exceeded

查看GC的一些数据信息

jstat -gc [pid]

间隔几秒再次查询,发现FGC(FullGC次数)列次数增加

查看堆内存状态

jmap -heap [pid]

初步锁定jvm内存泄露

排查存在内存泄露的代码

dumo快照

先dump一下jvm内存快照,用mat工具分析一下

jmap -dump:format=b,file=dump [pid]

file的值为输出dump文件的路径

导入mat分析工具

定位到大对象,是一个ConcurrentHashMap
image-1651080011365

展开ConcurrentHashMap
image-1651080078252

发现ConcurrentHashMap中所有的元素都是一个参数值不同的HQL(jpa封装的sql)缓存值

格式化HQL分析
image-1651080158816

image-1651080180783

可以看出该HQL 对应的 查询条件 由 IN 由OR where 对应 两个字段

在代码中查找定位相关代码

解决问题

参看文章

原因

hibernate中的QueryPlanCache会缓存sql,QueryPlanCache占用多大,基本上归结为IN子句中具有可变数量的值,而Hibernate试图缓存这些查询计划。如果in子句后面跟不同数量或数值,都会增加一条缓存(业务中确实有这么一条根据id进行记录更新操作)。从而缓存大量的sql导致heap内存溢出。

解决方案

在application.properties或yml文件增加以下配置:

#管理缓存中 ParameterMetadata 实例的数量(默认为 128)
spring.jpa.properties.hibernate.query.plan_parameter_metadata_max_size=5

#控制计划缓存中的最大条目数(默认为 2048)
spring.jpa.properties.hibernate.query.plan_cache_max_size=64

#设置缓存中保存的最大软引用数。将此值设置为 Integer.MAX_VALUE 以复制 5.1.1 及更早版本的行为。例如2048(默认)
spring.jpa.properties.hibernate.query.plan_cache_max_soft_references=1024

#设置缓存中保存的最大强引用数。例如128(默认)
spring.jpa.properties.hibernate.query.plan_cache_max_strong_references=64

spring.jpa.properties.hibernate.query.in_clause_parameter_padding=true
0

评论区