web-dev-qa-db-ja.com

削減方法Java同時モード障害と過度のgc

Javaでは、同時モードの障害は、同時コレクターが終身世代および永続世代から十分なメモリ空間を解放できなかったことを意味し、あきらめて完全なstop-the-world gcを開始する必要があります。最終結果は非常に高価になる可能性があります。

私はこの概念を理解していますが、
A)同時モード障害の原因は何ですか。
B)解決策は何ですか。

この種の不明瞭さは、ヒントをあまり気にせずにコードを記述/デバッグすることにつながり、多くの場合、特別な理由なしにFooからBarにそれらのパフォーマンスフラグを回避する必要があります。

ここで開発者からあなたの経験を学びたいですか?このようなパフォーマンスの問題が発生した場合、原因は何で、どのように対処しましたか?

コーディングの推奨事項がある場合は、あまり一般的にしないでください。ありがとう!

44
jimx

私が学んだCMSについての最初のことは、他のコレクターよりも多くのメモリが必要であるということです。約25〜50%が良い出発点です。これは、CMSがワールドコレクターが停止するような圧縮を行わないため、断片化を回避するのに役立ちます。第二に、ガベージコレクターを支援することを行います。 Integer.valueOfは、新しいIntegerではなく、匿名クラスを取り除き、内部クラスがアクセスできないもの(外部クラスではプライベート)にアクセスしないようにします。ゴミが少ないほど良い。 FindBugsを使用し、警告を無視しないことは、これに大いに役立ちます。

チューニングに関しては、いくつかのことを試す必要があることがわかりました。

-XX:+ UseConcMarkSweepGC

終身世代でCMSを使用するようJVMに指示します。

ヒープのサイズを修正します。-Xmx2048m -Xms2048mこれにより、GCがヒープの拡大や縮小などを行う必要がなくなります。

-XX:+ UseParNewGC

若い世代では、シリアルコレクションの代わりにパラレルを使用します。これは、特に非常に大きな若い世代を構成している場合に、マイナーコレクションを高速化します。大規模な若い世代は一般的には良いですが、古い世代のサイズの半分を超えないでください。

-XX:ParallelCMSThreads = X

cMSが並行して実行できることを実行しているときに使用するスレッドの数を設定します。

-XX:+ CMSParallelRemarkEnabled remarkEnabledはデフォルトでシリアルです。これにより速度が向上します。

-XX:+ CMSIncrementalModeにより、フェーズ間でGCを実行することにより、アプリケーションをさらに実行できます。

-XX:+ CMSIncrementalPacingは、JVMが時間の経過とともに収集する頻度を変更できるようにします

-XX:CMSIncrementalDutyCycleMin = X GCの実行に費やした最小時間

-XX:CMSIncrementalDutyCycle = Xこの時間の割合でGCを実行して開始

-XX:CMSIncrementalSafetyFactor = X

基本的に常に収集するように設定すると、一般に短い一時停止時間を取得できることがわかりました。ほとんどの作業は並行して行われるため、基本的には予測可能な一時停止が発生します。

-XX:CMSFullGCsBeforeCompaction = 1

これは非常に重要です。新しいコレクションを開始する前に、コレクションを常に完了するようにCMSコレクターに指示します。これがないと、大量の作業を捨てて再び開始する状況に陥ります。

-XX:+ CMSClassUnloadingEnabled

デフォルトでは、CMSはPermGenを数週間後にアプリを強制終了するまで成長させます。これはそれを止めます。ただし、PermGenは、Reflectionを使用する場合、String.internを誤用する場合、クラスローダーで何か悪いことをする場合、または他のいくつかの場合にのみ成長します。

生存しているオブジェクトが長いか短いか、生存できるスペース間でコピーするオブジェクトの量に応じて、生存率と保有期間も使用できます。すべてのオブジェクトが固定されていることがわかっている場合は、サイズが0のサバイバースペースを設定できます。1つの若い世代のコレクションを生き残ったものはすぐに終身在籍します。

22
Kevin Lafayette

「同時マークスイープガベージコレクターログの理解」

同時モード障害は、CMSInitiatingOccupancyFractionを低い値に設定することにより、古い世代のサイズを増やすか、より少ないヒープ占有率でCMSコレクションを開始することで回避できます。

ただし、アプリケーションで実際にメモリリークが発生している場合は、時間を買っているだけです。

高速な再起動と復旧が必要で、「高速」のアプローチが必要な場合は、CMSをまったく使用しないことをお勧めします。私は '-XX:+ UseParallelGC'を使い続けます。

"Garbage Collector Ergonomics" から

並列ガベージコレクター(UseParallelGC)は、少量のヒープの収集に過度の時間が費やされている場合、メモリ不足例外をスローします。この例外を回避するために、ヒープのサイズを増やすことができます。パラメーターを設定することもできます-XX:GCTimeLimit=time-limitおよび-XX:GCHeapFreeLimit=space-limit

12
fglez

時々OOMはかなり速く殺され、時には長いgc期間に苦しむことがあります(前回は10時間以上でした)。

メモリリークが問題の根本にあるように思えます。

CMSの障害は(私が理解しているように)OOMを引き起こしません。むしろ、JVMがあまりにも多くのコレクションを迅速に実行する必要があり、CMSが追いつかないために、CMSの障害が発生します。短期間に多くの収集サイクルが発生する状況の1つは、ヒープがほぼいっぱいになったときです。

本当に長いGC時間は奇妙に聞こえます...しかし、マシンがひどくスラッシングしている場合、理論的には可能です。ただし、ヒープがほぼいっぱいになっている場合、GCを繰り返し実行することはかなり妥当です。

ヒープが1)最大サイズであり、2)フルGCが完了した後もフルに近い場合に放棄するようにGCを構成できます。まだ実行していない場合は、これを試してください。問題を解決することはできませんが、少なくともJVMはOOMを迅速に取得し、サービスの再起動と回復を高速化できます。

[〜#〜] edit [〜#〜]-これを行うオプションは-XX:GCHeapFreeLimit=nnnここで、nnnは、GC後に解放する必要があるヒープの最小パーセンテージを示す0〜100の数値です。デフォルトは2です。オプションは、適切なタイトルの 「Java 6 JVMの-XXオプションの最も完全なリスト」 ページにリストされています。 (Sunのドキュメントには表示されない-XXオプションが数多くリストされています。残念ながら、このページにはオプションが実際に行うことに関する詳細はほとんどありません。)

アプリケーション/ webappにメモリリークがあるかどうかを確認することをお勧めします。存在する場合、それらのリークが検出されて修正されない限り、問題は解決しません。長期的には、Hotspot GCオプションをいじってもメモリリークは修正されません。

4
Stephen C

-XX:PretenureSizeThreshold=1m「大きな」オブジェクトをすぐに終身領域に移動させると、若い+ 1個の生存データ量をダンプしようとしない傾向があるため、若いGCと同時モードの障害が大幅に減少しました(xmn=1536m survivorratio=3 maxTenuringThreashould=5)完全なCMSサイクルが完了する前。はい、私のサバイバースペースは大きいですが、約2日に1回、それを必要とするアプリに何かが入ります(そして、1つのアプリに対して毎日12台のアプリサーバーを実行します)。

0
dave