Java – hibernate sqlfragment memory leak?
I deployed a simple webapp on the Tomcat server Webapp is a rest web service. Each web resource loads data from MySQL database and returns XML or JSON documents I use the following framework stack: Jersey (1.14) spring (3.1) hibernate (4.1) ehcache (2.5.1)
I tested webapp with JMeter: I started five threads to request web resources After a few minutes, the heap has started to slowly fill up to 99% and finally returned an oom exception I don't know if it's a memory leak, but when I see a lot of org. Org in the memory heap hibernate. hql. internal. ast. tree. Sqlfragment object?!!
/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>
Here are my JVM options:
JAVA_OPTS="-Xms1g -Xmx1g -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=30"
Solution
I updated my JVM from 1.6 update 21 to 1.6 update 38, and the leak seems to have been fixed
/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
Note: JDK update does not solve the problem!
I tested all rest resources with JMeter to determine which resource was leaking I found a resource, and now I can use JMeter to fill all the memory heap in less than 30 seconds I found HQL queries that create a large number of sqlfragments:
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();
Here is the number of sqlfragments just after starting Tomcat
jmap -histo:live 27472 | grep -i sqlFragment 608: 15 840 org.hibernate.hql.internal.ast.tree.sqlFragment
And the number of sqlfragments after one HTTP request is completely garbage
jmap -histo:live 27472 | grep -i sqlFragment 503: 37 2072 org.hibernate.hql.internal.ast.tree.sqlFragment
To quickly solve this problem, I rewrite the HQL request as 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();