【问题标题】:Hibernate SqlFragment memory leak?Hibernate SqlFragment 内存泄漏?
【发布时间】:2013-01-16 23:11:00
【问题描述】:

我在 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"

【问题讨论】:

  • HQL-&gt;SQL 似乎发生了内存泄漏。尝试在您的代码中找到 HQL 并检查代码。或者 mybe 这是一个休眠错误。

标签: java spring hibernate garbage-collection


【解决方案1】:

我将我的 jvm 从 1.6 update 21 更新到 1.6 update 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();

【讨论】:

    【解决方案2】:

    直方图是一个好的开始,现在您知道要查找什么了。

    接下来,收集堆转储并查看SqlFragment 实例的来源。使用Eclipse MAT 进行分析-这可能会向您显示该代码是“问题嫌疑人”,您可以从那里开始-分析它对这些类的输入/输出引用。还要检查终结器。

    此外,jProfiler 快照可以告诉您谁在分配 SqlFragment - 这将向您显示谁负责该分配 - 无论是您的代码还是休眠。

    此外,我还建议在 OOM 异常之前收集线程转储,以便您了解系统中发生的情况。

    【讨论】:

      猜你喜欢
      • 2017-08-31
      • 1970-01-01
      • 2014-04-03
      • 2013-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 2016-02-21
      相关资源
      最近更新 更多