10

16Gb の RAM、8 コア プロセッサ、およびすべて CentOS リリース 5.2 (Final) で実行されている Java 1.6 を搭載したマシンで、メモリを集中的に使用するアプリを実行しています。正確な JVM の詳細は次のとおりです。

java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)

次のコマンド ライン オプションを使用してアプリを起動しています。

java -XX:+UseConcMarkSweepGC -verbose:gc -server -Xmx10g -Xms10g ...

私のアプリケーションは JSON-RPC API を公開しており、私の目標は 25 ミリ秒以内にリクエストに応答することです。残念ながら、最大で 1 秒以上の遅延が見られます。これはガベージ コレクションが原因のようです。より長い例のいくつかを次に示します。

[GC 4592788K->4462162K(10468736K), 1.3606660 secs]
[GC 5881547K->5768559K(10468736K), 1.2559860 secs]
[GC 6045823K->5914115K(10468736K), 1.3250050 secs]

これらの各ガベージ コレクション イベントには、示されているガベージ コレクションの長さとほぼ同じ時間 (数ミリ秒以内) の API 応答の遅延が伴いました。

いくつかの典型的な例を次に示します (これらはすべて数秒以内に生成されました)。

[GC 3373764K->3336654K(10468736K), 0.6677560 secs]
[GC 3472974K->3427592K(10468736K), 0.5059650 secs]
[GC 3563912K->3517273K(10468736K), 0.6844440 secs]
[GC 3622292K->3589011K(10468736K), 0.4528480 secs]

問題は、UseConcMarkSweepGC がこれを回避するか、少なくとも非常にまれにするだろうと私が考えたことです。反対に、100 ミリ秒を超える遅延はほぼ 1 分に 1 回以上発生しています (ただし、1 秒を超える遅延はかなりまれであり、おそらく 10 分または 15 分に 1 回です)。

もう 1 つのことは、スレッドが一時停止されるのは FULL GC だけだと思っていましたが、これらは完全な GC ではないようです。

ほとんどのメモリは、ソフト参照を利用する LRU メモリ キャッシュによって占められていることに注意してください。

任意の支援やアドバイスをいただければ幸いです。

4

7 に答える 7

11

まず、Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuningのドキュメントをまだチェックしていない場合はチェックしてください。このドキュメントには次のように記載されています。

コンカレント コレクタは、実行中のアプリケーション スレッドでほとんどのトレースおよびスイープ作業を行うため、アプリケーション スレッドからは短い一時停止のみが見られます。ただし、Tenured世代がいっぱいになる前にコンカレント・コレクタが到達不能オブジェクトの再利用を完了できない場合、またはTenured世代の使用可能な空き領域ブロックで割当てが満たされない場合、アプリケーションは一時停止され、収集は次のコマンドで完了しますすべてのアプリケーション スレッドが停止しました。コレクションを同時に完了できないことは、並行モード障害と呼ばれ、並行コレクターのパラメーターを調整する必要があることを示します。

そして少し後に…

並行コレクターは、並行収集サイクル中にアプリケーションを 2 回一時停止します。

これらの GC があまり多くのメモリを解放していないように見えることに気付きました。おそらく、あなたのオブジェクトの多くは長命ですか?生成サイズやその他の GC パラメータを調整したい場合があります。10 ギガは多くの基準で巨大なヒープであり、このような巨大なヒープでは GC に時間がかかると素朴に予想します。それでも、1 秒というのは非常に長い一時停止時間であり、何かが間違っている (プログラムが大量の不要なオブジェクトを生成している、再利用が困難なオブジェクトを生成している、またはその他の何か) か、単に GC を調整する必要があることを示しています。

通常、GC を調整する必要がある場合は、最初に修正する必要がある他の問題があることを誰かに伝えます。しかし、このサイズのアプリケーションでは、「平均的なプログラマーよりもはるかに GC を理解する必要がある」領域に陥ると思います。

他の人が言ったように、ボトルネックがどこにあるかを確認するには、アプリケーションをプロファイリングする必要があります。PermGen は割り当てられたスペースに対して大きすぎますか? 不要なオブジェクトを作成していませんか? jconsole は、少なくとも VM に関する最小限の情報を表示するように機能します。出発点です。ただし、他の人が指摘しているように、これよりも高度なツールが必要になる可能性が非常に高いです。

幸運を。

于 2009-02-22T01:59:06.540 に答える
11

あなたがキャッシュしたいというあなたの願望に言及しているので、私はあなたの巨大なヒープのほとんどがそのキャッシュによって占められていると推測しています. キャッシュのサイズを制限して、tenured ジェネレーションをいっぱいにするほど大きくならないようにすることができます。SoftReferenceサイズを制限するために単独で頼らないでください。古い世代がソフト参照でいっぱいになると、古い参照はクリアされてガベージになります。新しい参照 (おそらく同じ情報への参照) が作成されますが、空き領域が不足しているためすぐに消去されます。最終的に、保有スペースはゴミでいっぱいになり、掃除する必要があります。

設定の調整も検討してください-XX:NewRatio。デフォルトは 1:2 で、ヒープの 3 分の 1 が新しい世代に割り当てられることを意味します。大きなヒープの場合、ほとんどの場合、これは多すぎます。古い世代のために 10 Gb ヒープの 9 Gb を保持する 9 のようなものを試してみてください。

于 2009-02-22T03:14:01.213 に答える
6

ヒープの一部がディスクにスワップアウトされていたことが判明したため、ガベージ コレクションはディスクから大量のデータをメモリに戻す必要がありました。

Linux の「swappiness」パラメーターを 0 に設定することでこれを解決しました (データをディスクにスワップアウトしないようにするため)。

于 2009-03-06T23:39:18.843 に答える
2

ここに、私が発見した重要な事柄がいくつかあります。

  • JSON-RPC は、多くのオブジェクトを生成できます。XML-RPC ほどではありませんが、それでも注意が必要です。いずれにせよ、1 秒あたり 100 MB のオブジェクトを生成しているように見えます。これは、GC が実行されている時間の割合が高く、ランダムなレイテンシが追加される可能性が高いことを意味します。GC がコンカレントであっても、ハードウェア/OS は、負荷がかかると理想的ではないランダムなレイテンシを示す可能性が非常に高くなります。
  • メモリバンクのアーキテクチャを見てください。Linux では、コマンドは numactl --hardware です。VM が複数のメモリ バンクに分割されている場合、GC 時間が大幅に増加します。(これらのアクセスの効率が大幅に低下する可能性があるため、アプリケーションの速度も低下します) メモリ サブシステムをよりハードに処理すればするほど、OS がメモリをシフトしなければならない可能性が高くなり (多くの場合、大量に)、結果として劇的な一時停止が発生します ( 100ミリ秒は驚くべきことではありません)。OS はアプリを実行するだけではないことを忘れないでください。
  • キャッシュのメモリ消費量を圧縮/削減することを検討してください。数 GB のキャッシュを使用している場合は、メモリ消費をこれまで以上に削減する方法を検討する価値があります。
  • メモリ割り当てトレースと CPU サンプリングを同時にオンにして、アプリをプロファイリングすることをお勧めします。これは非常に異なる結果をもたらす可能性があり、多くの場合、この種の問題の原因を示しています。

これらのアプローチを使用して、RPC 呼び出しのレイテンシーを200 マイクロ秒未満に短縮し、GC 時間を 1 ~ 3 ミリ秒に短縮して、呼び出しの 1/300 未満に影響を与えることができます。

于 2009-02-22T03:10:38.490 に答える
0

探し始めるいくつかの場所:

また、プロファイラーを介してコードを実行します。NetBeansのものが好きですが、他にもあります。gcの動作をリアルタイムで表示できます。Visual VMもそれを行います...しかし、私はまだそれを実行していません(理由を探しています...しかし、時間や必要性はまだありません)。

于 2009-02-22T00:47:01.207 に答える
0

GCViewerとプロファイラーもお勧めします。

于 2009-02-22T00:53:23.983 に答える
0

私は個人的にそのような巨大なヒープを使用したことはありませんが、Oracle/Sun Java 1.6.x の次のスイッチを使用して、一般的に非常に低いレイテンシーを経験しました。

-Xincgc -XX:+UseConcMarkSweepGC -XX:CMSIncrementalSafetyFactor=50
-XX:+UseParNewGC
-XX:+CMSConcurrentMTEnabled -XX:ConcGCThreads=2 -XX:ParallelGCThreads=2
-XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=5
-XX:GCTimeRatio=90 -XX:MaxGCPauseMillis=20 -XX:GCPauseIntervalMillis=1000

私の意見では、重要な部分は、テニュア世代には CMS を使用し、若い世代には ParNewGC を使用することです。さらに、これにより CMS にかなり大きな安全係数 (デフォルトは 50% ではなく 10%) が追加され、短い一時停止時間が要求されます。-XX:MaxGCPauseMillis25 ミリ秒の応答時間を目標にしているので、さらに小さい値に設定してみます。同時 GC に 3 つ以上のコアを使用することもできますが、それは CPU 使用率に見合わないと思います。

HotSpot JVM GC チート シートも確認してください。

于 2012-01-17T09:07:01.587 に答える