生产上某个服务一直无响应,频繁出现了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
展开ConcurrentHashMap
发现ConcurrentHashMap中所有的元素都是一个参数值不同的HQL(jpa封装的sql)缓存值
格式化HQL分析
可以看出该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
评论区