26

JavaEEアプリケーションでいくつかの深刻な問題が発生し始めました。具体的には、アプリケーションは起動後数分以内に旧世代のヒープの最大99%を実行します。OOMはスローされませんが、事実上、JVMは応答しません。jstatは、古い世代のサイズがまったく減少せず、ガベージコレクションが行われていないことを示しており、kill-3は次のように述べています。

Heap
 PSYoungGen      total 682688K, used 506415K [0xc1840000, 0xf3840000, 0xf3840000)
  eden space 546176K, 92% used [0xc1840000,0xe06cd020,0xe2da0000)
  from space 136512K, 0% used [0xe2da0000,0xe2da0000,0xeb2f0000)
  to   space 136512K, 0% used [0xeb2f0000,0xeb2f0000,0xf3840000)
 PSOldGen        total 1536000K, used 1535999K [0x63c40000, 0xc1840000, 0xc1840000)
  object space 1536000K, 99% used [0x63c40000,0xc183fff8,0xc1840000)

VMオプションは次のとおりです。

-Xmx2300m -Xms2300m -XX:NewSize=800m -XX:MaxNewSize=800m -XX:SurvivorRatio=4 -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+UseParallelGC -XX:ParallelGCThreads=4 

(問題を解決するために、2300mヒープ/ 1800m新世代から変更しました)

「メモリ不足」状態になったら(永久に取得)、JVMのヒープダンプを取得し、その上でEclipseMemoryAnalyzerを実行しました。

結果はかなり面白いです。約200Mbはあらゆる種類のオブジェクトで占められていますが(他のものよりも所有しているものもあります)、残りの1.9Gbはすべて到達不能です(大部分がGSONオブジェクトで占められていることは注目に値しますが、そうではないと思います何かの兆候は、サーバーの操作中に多くのGSONオブジェクトを解約したことだけを示しています)。

VMに到達不能なオブジェクトが非常に多くあり、それらをまったく収集できない理由についての説明はありますか?

JVM:

$ /0/bin/java -version
java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06)
Java HotSpot(TM) Server VM (build 20.12-b01, mixed mode)

システムがこのストールに到達すると、冗長なGCが出力し続けるものは次のとおりです。

922.485: [GC [1 CMS-initial-mark: 511999K(512000K)] 1952308K(2048000K), 3.9069700 secs] [Times: user=3.91 sys=0.00, real=3.91 secs] 
926.392: [CMS-concurrent-mark-start]
927.401: [Full GC 927.401: [CMS927.779: [CMS-concurrent-mark: 1.215/1.386 secs] [Times: user=5.84 sys=0.13, real=1.38 secs] (concurrent mode failure): 511999K->511999K(512000K), 9.4827600 secs] 2047999K->1957315K(2048000K), [CMS Perm : 115315K->115301K(262144K)], 9.4829860 secs] [Times: user=9.78 sys=0.01, real=9.49 secs] 
937.746: [Full GC 937.746: [CMS: 512000K->511999K(512000K), 8.8891390 secs] 2047999K->1962252K(2048000K), [CMS Perm : 115302K->115302K(262144K)], 8.8893810 secs] [Times: user=8.89 sys=0.01, real=8.89 secs] 

解決済み

Paul Belloraが示唆したように、これは、JVM内で作成されたオブジェクトの量が多すぎて短期間で発生したことが原因でした。この時点で、デバッグは非常に面倒になります。私がやったことは、カスタムJVMエージェントを使用してクラスをインストルメント化することです。インストルメンテーションは、メソッドとコンストラクターの呼び出しをカウントします。次に、カウントを調べた。目立たない単一の操作で約200万のオブジェクトが作成され、特定の個別のメソッドが約150万回トリガーされることがわかりました(いいえ、ループはありませんでした)。操作自体は、他の操作と比較して遅いことによって識別されました。ホットスポットプロファイラー(visualVMのようなもの)も使用できますが、私はそれらにさまざまな問題を抱えていたため、自分で作成することになりました。

私はまだJVMの振る舞いは謎だと思います。ガベージコレクターがストールし、それ以上メモリをクリーンアップしないように見えますが、メモリアロケータはそれを期待しています(したがって、OOMはスローされません)。代わりに、到達不能なメモリをすべてクリアすることを期待していました。しかし、アプリケーションの動作は、時間の大部分がとにかくガベージコレクションに費やされていたため、それほど良くはありませんでした。

ヘルプに使用したエージェントは、https ://github.com/veselov/MethodCountAgentにあります。洗練されたソフトウェアとはほど遠いです。

4

2 に答える 2

14

VMに到達不能なオブジェクトが非常に多くあり、それらをまったく収集できない理由についての説明はありますか?

(コメントでの交換に基づくと)これは従来のメモリリークではなく、GCが現在のアーキテクチャに追いつくのに苦労するように、新しいオブジェクトを継続的にスパムするロジックの一部のようです。

原因は、たとえば、何度も何度も行われているAPIリクエストであるか、または、説明した無限のページネーションシナリオのような誤った状態で「スタック」している可能性があります。どちらの状況でも、何百万もの応答gsonオブジェクト(Stringsを指す(sを指すchar[]))がインスタンス化され、GCの対象になります。

私が言ったように、問題の要求を切り分けてから、デバッグして測定を行い、これがアプリケーションまたはそのライブラリの一部のバグまたはスケーラビリティの問題であるかどうかを判断する必要があります。

于 2013-01-17T05:41:50.947 に答える
2

リストされている統計に基づいて、1.9G の到達不能データがあるとは信じがたいと思います。GC Overhead Limit Reachedのように見えます。

検討

937.746: [フル GC 937.746: [CMS: 512000K->511999K(512000K), 8.8891390 秒] 2047999K->1962252K(2048000K), [CMS パーマ: 115302K->115302K(262148 秒)] [ユーザー時間: 8148 秒]: 3 8.89 sys=0.01, real=8.89 秒]

これが当てはまる場合、フル GC は 85K のデータを解放します。到達不能コードが 1.9G ある場合は、 が表示されます2047999 -> ~300000

また

object space 1536000K, 99% 

何かがメソッドを回避するような方法で作成および保存され、おそらく永遠に存続していることを意味します。

1.9G の到達不能データがあるというより多くの証拠を確認する必要があります。

于 2013-01-17T18:42:48.133 に答える