加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – Hibernate SqlFragment内存泄漏?

发布时间:2020-12-14 19:33:09 所属栏目:Java 来源:网络整理
导读:我在Tomcat服务器上部署了一个简单的webapp. webapp是一个REST Web服务,每个Web资源从 MySQL数据库加载数据并返回XML或JSON文档.我使用以下框架堆栈:Jersey(1.14)Spring(3.1)Hibernate(4.1)EHCache(2.5.1). 我用jMeter测试了webapp:我启动了5个线程来请求W
我在Tomcat服务器上部署了一个简单的webapp. webapp是一个REST Web服务,每个Web资源从 MySQL数据库加载数据并返回XML或JSON文档.我使用以下框架堆栈:Jersey(1.14)Spring(3.1)Hibernate(4.1)EHCache(2.5.1).

我用jMeter测试了webapp:我启动了5个线程来请求Web资源.几分钟后,堆已经开始缓慢填充达到99%并最终返回OOM异常.我不知道它是否是内存泄漏但是当我在内存堆中看到大量的org.hibernate.hql.internal.ast.tree.SqlFragment对象时?!!

/usr/java/jdk/bin/jmap -histo:live 17047 > /tmp/histo.txt

 num     #instances         #bytes  class name
----------------------------------------------
   1:        720143       69133728  org.hibernate.hql.internal.ast.tree.SqlFragment
   2:        510537       63559320  [C
   3:        360221       34581216  org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode
   4:        704652       33823296  java.util.HashMap$Entry
   5:        360223       31699624  org.hibernate.hql.internal.ast.tree.SqlNode
   6:        697354       27894160  java.lang.String
   7:        370975       26710200  org.hibernate.hql.internal.ast.tree.Node
   8:        171241       25623320  <constMethodKlass>
   9:        208125       24948176  [Ljava.lang.Object;
  10:        171241       20568632  <methodKlass>
  11:         16012       17827384  <constantPoolKlass>
  12:        383070       16623136  [I
  13:         34829       15170176  [Ljava.util.HashMap$Entry;
  14:        226869       12885896  <symbolKlass>
  15:         16012       12590168  <instanceKlassKlass>

这里是我的jvm选项:

JAVA_OPTS="-Xms1g -Xmx1g -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=30"

解决方法

我将我的jvm从1.6更新21更新到1.6更新38,泄漏似乎已修复.
现在我在压力期间只有17个SQLFragment实例.
/usr/java/jdk/bin/jmap -histo:live 5612 | grep org.hibernate.hql.internal.ast.tree.SqlFragment
 912:            17            952  org.hibernate.hql.internal.ast.tree.SqlFragment
/usr/java/jdk/bin/jmap -histo:live 5612 | grep org.hibernate.hql.internal.ast.tree.SqlFragment
 910:            17            952  org.hibernate.hql.internal.ast.tree.SqlFragment
/usr/java/jdk/bin/jmap -histo:live 5612 | grep org.hibernate.hql.internal.ast.tree.SqlFragment
 980:            17            952  org.hibernate.hql.internal.ast.tree.SqlFragment

注意:JDK更新没有解决问题!

我用jmeter测试了所有REST资源,以确定哪个资源泄漏.
我找到了1个资源,现在我可以使用jmeter在不到30秒内填满所有内存堆.
我找到了创建大量SqlFragment的HQL查询:

String q = "select p from PhysicalItem p where p.product.id=:itemid and p.fileType in (:filetypes) order by p.id desc";
return sessionFactory.getCurrentSession().createQuery(q).setParameter("itemid",logicalItemID).setParameterList("filetypes",fileTypes).list();

这里是刚刚启动Tomcat后SqlFragment的数量.

jmap -histo:live 27472 | grep -i SqlFragment
 608:            15            840  org.hibernate.hql.internal.ast.tree.SqlFragment

并且1个http请求完全垃圾后的SqlFragment数量

jmap -histo:live 27472 | grep -i SqlFragment
 503:            37           2072  org.hibernate.hql.internal.ast.tree.SqlFragment

为了快速解决这个问题,我将HQL请求重写为SQL:

String sql = "select p.* from physical_item p where p.id_logical = :itemid and p.file_type in (:filetypes) order by p.id desc";
            List<String> names = new ArrayList<String>();
            for (FileType fileType : fileTypes) {
                names.add(fileType.getName());
            }
            return sessionFactory.getCurrentSession()
                                .createSQLQuery(sql)
                                .addEntity(PhysicalItem.class)
                                .setParameter("itemid",logicalItemID)
                                .setParameterList("filetypes",names)
                                .list();

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读