hibernate QueryPlanCache 引发的heap区内存溢出

转载自:https://blog.csdn.net/dream_lixiang/article/details/77248292

叙述

有一个项目中用到了hibernate作为数据持久层,当项目完成,使用loadrunner进行并发测试的时候,当测试跑了几天,就因为内存溢出挂掉了。当对奔溃场景进行重现的时,利用了JvisualVM工具对其进行监控,发现了其heap区内存一直在持续增长,利用heap dump分析其内存情况,发现有几种类型的对象增长异常。当时针对监控的问题还给领导发了一封邮件,信息如下:

分析

通过下图可以看到,heap区的变化就相当明显:

但是增长异常的对象类型像ConcurrentHashMap$HashEntry、char[]、Object我根本没有直接用到,程序中的String也不存在内存泄漏的问题,这让我很头疼。于是使用了MAT对heap dump文件进行分析,找到了异常对象的堆栈

SessionFactoryImpl是我程序中直接依赖的,我看到了SessionFactoryImpl中的QueryPlanCache的体积特别庞大,此次的内存溢出问题的罪魁祸首就是它。通过它的名字,就可以知道它是用来缓存查询计划的,也就是缓存sql语句,但是为什么会这么大喃?后来我在外网上发现有网友出现同样的问题(

http://stackoverflow.com/questions/31557076/spring-hibernate-query-plan-cache-memory-usage),他的原因是因为in子句,

Using Hibernate 4.2 and MySQL in a project with an in-clause query such as: select t from Thing t where t.id in (?)

Hibernate caches these parsed HQL queries. Specifically the Hibernate SessionFactoryImpl has QueryPlanCache with queryPlanCache and parameterMetadataCache. But this proved to be a problem when the number of parameters for the in-clause is large and varies.

These caches grow for every distinct query. So this query with 6000 parameters is not the same as 6001.

The in-clause query is expanded to the number of parameters in the collection. Metadata is included in the query plan for each parameter in the query, including a generated name like x10_, x11_ , etc.

Imagine 4000 different variations in the number of in-clause parameter counts, each of these with an average of 4000 parameters. The query metadata for each parameter quickly adds up in memory, filling up the heap, since it can't be garbage collected.

This continues until all different variations in the query parameter count is cached or the JVM runs out of heap memory and starts throwing java.lang.OutOfMemoryError: Java heap space.

大概的意思就是,QueryPlanCache会缓存sql,以便于后边的相同的sql重复编译,如果in后的参数不同,hibernate会把其当成不同的sql进行缓存,从而缓存大量的sql导致heap内存溢出。我的程序中没有使用in,但通过查看程序,我发现我的一条hql中同时采用paramter string拼接和占位符两种方式,这样会不会因为每一个paramter string都不同,hibernate认为这是不同的hql从而进行大量缓存喃?于是我全部采用站位符的方式,再进行测试,发现程序heap内存一直处于稳定状态,问题解决。

解决方案

通过设置缓存最大值来进行限制,不设置默认是2G。

spring:
  jpa:
    properties:
      hibernate:
        query:
          plan_cache_max_size: 64
          plan_parameter_metadata_max_size: 32
          plan_cache_max_soft_references: 1024
          plan_cache_max_strong_references: 64

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值