5

Tomcat サーバーにデプロイされた単純な webapp があります。webapp は REST Web サービスであり、各 Web リソースは MySQL データベースからデータをロードし、XML または JSON ドキュメントを返します。次のフレームワーク スタックを使用します: Jersey (1.14) + Spring (3.1) + Hibernate (4.1) + EHCache (2.5.1)。

jMeter で webapp をテストしました: web リソースを要求するために 5 つのスレッドを開始しました。数分後、ヒープがゆっくりといっぱいになり始めて 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"
4

2 に答える 2

3

jvm を 1.6 update 21 から 1.6 update 38 に更新しましたが、リークは修正されたようです。現在、ストレス期間中の SQLFragment のインスタンスは 17 個しかありません。

/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 の更新では問題は解決しませんでした!!

すべての REST リソースを jmeter でテストして、リークしているリソースを特定しました。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();
于 2013-01-11T10:17:03.920 に答える
0

ヒストグラムは良い出発点です。これで、何を探すべきかがわかりました。

次に、ヒープ ダンプを収集し、SqlFragmentインスタンスがどこから来ているかを確認します。で分析しますEclipse MAT-これはおそらくそのコードを「問題の容疑者」として示し、そこから行くことができます-これらのクラスへのイン/アウト参照を分析します。ファイナライザーも確認してください。

また、jProfiler スナップショットは、誰が割り当てているSqlFragmentかを示すことができます。これにより、その割り当ての責任者が誰であるかが示されます。それがコードか休止状態かに関係なく。

さらに、OOM 例外が発生する前にスレッド ダンプを収集することもお勧めします。これにより、システムで何が起こっているかがわかります。

于 2013-01-10T20:56:28.500 に答える