21

Tomcat7で実行されているJavaWebアプリケーションがあり、メモリリークがあるようです。アプリケーションの平均メモリ使用量は、負荷がかかっているときに時間の経過とともに直線的に増加します(JConsoleを使用して決定)。メモリ使用量がプラトーに達すると、パフォーマンスが大幅に低下します。応答時間は約100msから[300ms、2500ms]になるため、これは実際に実際の問題を引き起こしています。

私のアプリケーションのJConsoleメモリプロファイル: アプリケーションメモリプロファイル

VisualVMを使用すると、メモリの少なくとも半分が文字配列(つまり、char [])によって使用されており、文字列のほとんど(それぞれ、300,000インスタンスのほぼ同じ数)が次のいずれかであることがわかります。「割り当ての失敗」 、「コピー」、「マイナーGCの終了」、これらはすべてガベージコレクション通知に関連しているようです。私の知る限り、アプリケーションはガベージコレクターをまったく監視していません。VisualVMはこれらの文字列のGCルートを見つけることができないため、これを追跡するのに苦労しています。

メモリアナライザのヒープダンプ: ヒープダンプ、到達不能メモリ

なぜそのようなメモリ使用量のプラトーになるのか説明することはできませんが、パフォーマンスが低下するとパフォーマンスが低下する理由については理論があります。メモリが断片化されている場合、アプリケーションは、新しい要求を処理するために連続したメモリブロックを割り当てるのに長い時間がかかる可能性があります。

これを組み込みのTomcatサーバーステータスアプリケーションと比較すると、メモリは増加し、で横ばいになりますが、私のアプリケーションのように高い「フロア」には到達しません。また、到達不能なchar[]の数も多くありません。

TomcatサーバーステータスアプリケーションのJConsoleメモリプロファイル: ここに画像の説明を入力してください

Tomcatサーバーステータスアプリケーションのメモリアナライザヒープダンプ: ここに画像の説明を入力してください

これらの文字列はどこに割り当てることができ、なぜガベージコレクションされないのですか?これに影響を与える可能性のあるTomcatまたはJavaの設定はありますか?これに影響を与える可能性のある特定のパッケージはありますか?

4

8 に答える 8

7

tomcat\bin\setenv.batから次の JMX 構成を削除しました。

set "JAVA_OPTS=%JAVA_OPTS% 
    -Dcom.sun.management.jmxremote=true 
    -Dcom.sun.management.jmxremote.port=9090
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=false"

詳細なメモリ ヒープ ダンプを取得することはできなくなりましたが、メモリ プロファイルははるかに良く見えます。 ここに画像の説明を入力

24 時間後、メモリ プロファイルは同じように見えます。 ここに画像の説明を入力

于 2012-12-04T19:09:55.187 に答える
3

プラトーは、利用可能なメモリがデフォルトのパーセンテージしきい値を下回り、フル GC が発生するために発生します。これは、JVM がメモリを見つけて解放しようとしている間、常に一時停止しているため、パフォーマンスが低下する理由を説明しています。

通常はオブジェクト キャッシュを確認することをお勧めしますが、あなたの場合、Tomcat インスタンス + webapp にはヒープ サイズが小さすぎると思います。ヒープを 1G ( -Xms1024m -Xmx1024m) に増やしてから、メモリ使用量を再度確認することをお勧めします。

それでも同じ種類の動作が見られる場合は、別のヒープ ダンプを取得し、String と Char の後に最大のコンシューマーを確認する必要があります。私の経験では、これは通常キャッシュメカニズムです。メモリをさらに増やすか、可能であればキャッシュ ストアを減らしてください。一部のキャッシュはオブジェクトの数のみを定義するため、キャッシュされた各オブジェクトの大きさを理解する必要があります。

メモリ使用量を理解したら、それを再び下げることができるかもしれませんが、私見では 512MB が最小です。

アップデート:

GC によってクリーンアップされる必要があるため、到達不能オブジェクトについて心配する必要はありません。また、タイプ別の最大のコンシューマーが String と Char であることは正常です。ほとんどのオブジェクトには何らかの種類の String が含まれるため、String と Char が頻度で最も一般的であることは理にかなっています。文字列を含むオブジェクトを保持するものを理解することが、メモリの消費者を見つけるための鍵です。

于 2012-11-26T17:57:59.343 に答える
3

ヒープの分析に memoryAnalyzer を使用することをお勧めします。これにより、はるかに多くの情報が得られます。
http://www.eclipse.org/mat/ スタンドアロン アプリケーションと Eclipse 組み込みアプリケーションがあります。アプリケーションで jmap を実行し、これで結果を分析するだけです。

于 2012-11-21T11:41:11.077 に答える
2

すべての Java インストールに付属するjvisualvmをお勧めします。プログラムを開始し、Web アプリケーションに接続します。Monitor -> Heap Dumpに移動します。少々お時間をいただく場合がございます(サイズにより異なります)。Heap Dump を介したナビゲーションは非常に簡単ですが、その意味は自分で理解する必要があります (それほど複雑ではありません)。

Classes (heapdump 内) に移動し、 java.lang.Stringを選択し、 Show in Instances Viewを右クリックします。その後、左側のテーブルに、システムで現在アクティブな 文字列インスタンスが表示されます。1 つのStringインスタンスをクリックすると、右側のテーブルの右上部分にStringののように、いくつかのStringプリファレンスが表示されます。

右側の表の右下に、この Stringインスタンスがどこから参照されているかが表示されます。ここで、ほとんどの *String* がどこから参照されているかを確認する必要があります。しかし、あなたのケース (176/210、すぐに問題を引き起こすいくつかのStringの例を見つける可能性が高い) では、問題がどこにあるのかを調べた後、明らかになるはずです。

于 2012-11-26T17:06:25.633 に答える
2

まったく別のアプリケーションで同じ問題に遭遇したので、おそらく tomcat7 のせいではありません。メモリ アナライザーは、プロセス (約 2 か月間実行されている) で 10M の到達不能な String インスタンスを示し、それらのほとんどまたはすべてがガベージ コレクションに関連する値を持っています (たとえば、「割り当てエラー」、「マイナー GC の終了」)。

メモリーアナライザー

メモリーアナライザー

フル GC が 2 秒ごとに実行されるようになりましたが、これらの文字列は収集されません。私の推測では、GC コードでバグが発生したと思われます。次の Java バージョンを使用します。

$ java -version
java version "1.7.0_06"
Java(TM) SE Runtime Environment (build 1.7.0_06-b24)
Java HotSpot(TM) 64-Bit Server VM (build 23.2-b09, mixed mode)

および次の VM パラメータ:

-Xms256m -Xmx768m -server -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:NewSize=32m -XX:MaxNewSize=64m
-XX:SurvivorRatio=8 -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails 
-Xloggc:/path/to/file
于 2012-12-04T11:36:18.503 に答える
1

偶然、Tomcat の conf/catalina.properties ファイルで、文字列キャッシュを有効にする次の行を見つけました。それらのいずれかをオンにしている場合、これはあなたのケースに関連している可能性があります。他の人がこの機能を使用するよう警告しているようです。

tomcat.util.buf.StringCache.byte.enabled=true
#tomcat.util.buf.StringCache.char.enabled=true
#tomcat.util.buf.StringCache.trainThreshold=500000
#tomcat.util.buf.StringCache.cacheSize=5000
于 2013-09-26T11:37:48.497 に答える
1

MAT を使用してみてください。ヒープダンプを解析するときに、到達不能なオブジェクトを削除しないようにしてください。

これを行うには、こちらのチュートリアルに従ってください。

次に、簡単な Mem Leak Analysis を実行できます (これは良いチュートリアルです)。

そうすれば、すぐに根本原因にたどり着くはずです。

于 2013-10-11T20:37:49.827 に答える
0

不明確に聞こえるかもしれませんが、候補の 1 つは JSF でした。しかし、ハッシュマップもリークすると予想していました。

JSF を使用する必要があります: web.xmlで次を試すことができます。

  • javax.faces.STATE_SAVING_METHODクライアント
  • com.sun.faces.numberOfViewsInSession 0
  • com.sun.faces.numberOfLogicalViews 1

ツールに関しては、 JavaMelodyは継続的な統計には興味深いかもしれませんが、努力が必要です。

于 2012-11-26T16:58:00.740 に答える