web-dev-qa-db-ja.com

G1ガベージコレクター:完全なGCが実行されるまで、Perm Genが無制限にいっぱいになる

JBoss 7アプリケーションサーバーで実行されているかなり大きなアプリケーションがあります。以前はParallelGCを使用していましたが、ヒープが大きく(5 GB以上)、通常はほぼいっぱいになっている一部のサーバーで問題が発生し、非常に長いGCの休止が頻繁に発生しました。

最近、アプリケーションのメモリ使用量を改善し、いくつかのケースでは、アプリケーションが実行される一部のサーバーにさらにRAM=を追加しましたが、これらを作成するためにG1への切り替えを開始しました一時停止の頻度が少なくなったり短くなったりしています。状況は改善されているようですが、以前は発生しなかった奇妙な動作が見られます(ParallelGCを使用)。PermGenはすぐにいっぱいになり、最大値に達するとフルGCがトリガーされます。これにより、通常、アプリケーションスレッドで長い一時停止が発生します(場合によっては、1分以上)。

数か月間、512 MBの最大パーマサイズを使用しており、分析中、ParallelGCを使用すると、パーマサイズは通常、約390 MBで増加しなくなります。ただし、G1に切り替えた後、上記の動作が発生し始めました。最大パーマサイズを1 GBに、さらには1.5 GBに増やしてみましたが、それでもフルGCが発生しています(頻度は低いです)。

このリンク で、使用しているプロファイリングツールのスクリーンショットをご覧いただけます(YourKit Java Profiler)。フルGCがトリガーされたときのEdenおよびOld Genには多くの空き領域がありますが、Permサイズは最大です。Permサイズとロードされたクラスの数は、フルGCの後で大幅に減少しますが、それらは再び増加し始め、サイクルが繰り返されます。コードキャッシュは正常です。 38 MBを超えることはありません(この場合は35 MBです)。

以下は、GCログのセグメントです。

2013-11-28T11:15:57.774-0300:64445.415:[フルGC 2126M-> 670M(5120M)、23.6325510秒] [エデン:4096.0K(234.0M)-> 0.0B(256.0M)生存者:22.0M- > 0.0Bヒープ:2126.1M(5120.0M)-> 670.6M(5120.0M)] [時間:user = 10.16 sys = 0.59、real = 23.64秒]

完全なログ ここ を確認できます(サーバーを起動してから、完全なGCの数分後まで)。

ここにいくつかの環境情報があります:

Javaバージョン「1.7.0_45」

Java(TM)SEランタイム環境(ビルド1.7.0_45-b18)

Java HotSpot(TM)64ビットサーバーVM(ビルド24.45-b08、混合モード)

起動オプション:-Xms5g -Xmx5g -Xss256k -XX:PermSize=1500M -XX:MaxPermSize=1500M -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy -Xloggc:gc.log

だからここに私の質問があります:

  • これはG1で予想される動作ですか?私は誰かが非常によく似た質問をし、G1がPerm Genでインクリメンタルコレクションを実行すべきだと言っている別の投稿をウェブ上で見つけましたが、答えはありませんでした...

  • 起動パラメーターを改善/修正できるものはありますか?サーバーには8 GBのRAMがありますが、ハードウェアが不足しているようではありません。完全なGCがトリガーされるまでアプリケーションのパフォーマンスは良好です。つまり、ユーザーが大きな遅延を経験して不満を感じ始めます。

30
Jose Otavio

Perm Genの増加の原因

  • 多くのクラス、特にJSP。
  • 多くの静的変数。
  • クラスローダーのリークがあります。

知らない人のために、PremGenがどのようにいっぱいになるかを考える簡単な方法を次に示します。若い世代は物事が期限切れになるのに十分な時間がないため、古い世代のスペースに移動します。 Perm Genは、YoungおよびOld Genのオブジェクトのクラスを保持します。YoungまたはOld Genのオブジェクトが収集され、クラスが参照されなくなると、Perm Genから「アンロード」されます。 Old GenはGCを取得せず、Perm Genも実行しません。満杯になると、完全停止のGCが必要になります。詳細は 永続的な世代の提示 を参照してください。


CMSへの切り替え

G1を使用していることは承知していますが、並行マークスイープ(CMS)のローポーズコレクター-XX:+UseConcMarkSweepGCに切り替える場合は、-XX:+CMSClassUnloadingEnabledを追加して、クラスのアンロードと永続的な世代のコレクションを有効にしてみてください。


隠された問題 '

JBossを使用している場合、RMI/DGCのgcIntervalは1分に設定されています。 RMIサブシステムは、1分に1回フルガベージコレクションを強制します。これにより、若い世代に集められるのではなく、昇進が強制されます。

GCが適切な収集を行うためには、24時間ではなくても少なくとも1時間に変更する必要があります。

-Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000

すべてのJVMオプションのリスト

すべてのオプションを表示するには、これをcmd行から実行します。

Java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version

JBossが使用しているものを確認したい場合は、standalone.xmlに以下を追加する必要があります。すべてのJVMオプションとその設定内容のリストが表示されます。注:使用するには、JVM内にある必要があります。外部で実行すると、JBossが実行されているJVMで何が起こっているかがわかりません。

set "Java_OPTS= -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal %Java_OPTS%"

変更されたフラグのみに関心がある場合に使用するショートカットがあります。

-XX:+PrintcommandLineFlags

診断

jmap を使用して、永続的な生成スペースを消費しているクラスを判別します。出力が表示されます

  • クラスローダー
  • クラス数
  • バイト
  • 親ローダー
  • 生きている/死んでいる
  • タイプ
  • 合計

    jmap -permstat JBOSS_PID  >& permstat.out
    

JVMオプション

これらの設定は私にとってはうまくいきましたが、システムの設定方法とアプリケーションの動作に応じて、それらが適切かどうかが決まります。

  • -XX:SurvivorRatio=8 –サバイバースペースの比率を1:8に設定して、サバイバースペースを大きくします(比率が小さいほどスペースが大きくなります)。 SurvivorRatioは、1つのサバイバースペースと比較したエデンスペースのサイズです。サバイバースペースが大きいほど、寿命の短いオブジェクトが若い世代で死ぬ時間が長くなります。

  • -XX:TargetSurvivorRatio=90 –デフォルトの50%ではなく、90%のサバイバースペースを使用できるため、サバイバースペースメモリの使用率が向上します。

  • -XX:MaxTenuringThreshold=31 –若い世代から古い世代への早期昇進を防ぐため。寿命の短いオブジェクトをより若い期間で死ぬことを許可します(したがって、昇進を避けます)。この設定の結果、コピーする追加のオブジェクトが原因で、マイナーなGC時間が長くなる可能性があります。この値とサバイバースペースのサイズは、サバイバースペース間でのコピーのオーバーヘッドと、長期間存続する予定のオブジェクトのバランスを取るように調整する必要がある場合があります。 CMSのデフォルト設定はSurvivorRatio = 1024およびMaxTenuringThreshold = 0であり、これにより、スカベンジのすべてのサバイバーがプロモートされます。これは、古い世代を収集する単一の同時スレッドに大きな負荷をかける可能性があります。注:-XX:+ UseBiasedLockingと共に使用する場合、この設定は15にする必要があります。

  • -XX:NewSize=768m –初期の若い世代のサイズを指定できます

  • -XX:MaxNewSize=768m –若い世代の最大サイズを指定できます

以下は、より広範な JVMオプション リストです。

31
Joshua Wilson

これはG1で予想される動作ですか?

それは驚くべきことではありません。基本的な仮定は、permgenに入れられたものはほとんど決してゴミにならないということです。そのため、permgen GCは「最後の手段」になると期待できます。つまり、フルGCに強制された場合にのみ、JVMが実行することです。 (OK、この議論は証明のどこにもありません...しかし、それは以下と一致しています。)

他のコレクターが同じ行動をしているという多くの証拠を見てきました。例えば.

私は誰かが非常によく似た質問をし、G1がPerm Genでインクリメンタルコレクションを実行すべきだと言っている別の投稿をウェブ上で見つけましたが、答えはありませんでした...

同じ記事を見つけたと思います。しかし、それが可能でなければならないべきだという誰かの意見は、実際には有益ではありません。

起動パラメーターを改善/修正できるものはありますか?

疑わしい。私の理解では、これはpermgen GC戦略に固有のものです。

最初に多くのpermgenを使用しているものを追跡して修正することをお勧めします...またはJava 8に切り替えると、permgenヒープはもうありません:参照 JDK 8でのPermGenの削除

Permgenリークは考えられる1つの説明ですが、他にもあります。例えば.

  • String.intern()の乱用
  • 多くの動的クラス生成を行っているアプリケーションコード。例えばDynamicProxyを使用して、
  • 巨大なコードベース...ただし、観察しているようにpermgenchurnは発生しません。
2
Stephen C

JVMオプションをランダムに試す前に、最初にPermGenが大きくなる根本的な原因を見つけようとしました。

  • クラスローディングのロギングを有効にして(-verbose:class、-XX:+ TraceClassLoading -XX:+ TraceClassUnloading、...)、出力をチェックアウトすることができます
  • テスト環境では、クラスが読み込まれるときに(JMX経由で)監視を試すことができます(Java.lang:type = ClassLoading LoadedClassCount)。これは、アプリケーションのどの部分が原因であるかを見つけるのに役立つ場合があります。
  • また、JVMツールを使用してすべてのクラスを一覧表示することもできます(申し訳ありませんが、私はまだjrockitを使用しており、そこでjrcmdを使用します。オラクルがそれらの便利な機能をHotspotに移行したことを願っています...)

要約すると、何が非常に多くのクラスを生成するかを調べ、それを削減する方法/ GCを調整する方法を考えます。

乾杯、ディモ

1
mnp

私は 上記の答え に同意します。これは、実際にpermgenを満たしているものを実際に見つけ出すべきであり、根本的な原因を見つけたいのは、クラスローダーのリークに関するものだと強く思います。

this thread がJBossフォーラムにあり、そのような診断されたケースのいくつかを通過し、それらがどのように修正されたかを示します。 この回答この記事 は、一般的な問題についても説明しています。その記事には、おそらくあなたが実行できる最も簡単なテストについての言及があります:

症状

これは、アプリケーションサーバーを再起動せずにアプリケーションを再デプロイした場合にのみ発生します。 JBoss 4.0.xシリーズは、このようなクラスローダーリークの影響を受けていました。その結果、JVMがPermGenメモリを使い果たしてクラッシュする前に、アプリケーションを2回以上再デプロイできませんでした。

解決

このようなリークを特定するには、アプリケーションをアンデプロイしてから、フルヒープダンプをトリガーします(その前に必ずGCをトリガーしてください)。次に、ダンプ内にアプリケーションオブジェクトが見つかったかどうかを確認します。もしそうなら、彼らのルートへの参照をたどると、あなたのクラスローダーリークの原因を見つけるでしょう。 JBoss 4.0の場合、唯一の解決策は再デプロイのたびに再起動することでした。

これは、再デプロイメントが関連していると思われる場合に最初に試してみるものです。 このブログ投稿 は以前のものであり、同じことを行っていますが、詳細についても議論しています。投稿に基づいて、実際には何も再デプロイしていない可能性がありますが、permgenはそれ自体で一杯になっています。その場合、クラスの検査+ permgenに追加された他のすべての方法が可能です(以前の回答ですでに述べたように)。

それでも洞察が得られない場合は、次のステップとして、 plumbrツール を試してみます。彼らはある種の あなたのためにリークを見つけることの保証 も持っています。

1
eis