web-dev-qa-db-ja.com

JBoss 7、Java.lang.OutOfMemoryError:PermGenスペース

CPU使用率が制限に達し、JBossが再起動を必要とするこのエラーが発生しました(Java.lang.OutOfMemoryError: PermGen space)。

MaxPermSizeを増やす古いJBossバージョンのソリューションを見つけました。 JBoss7についても同じことが言えます。

再び問題に直面しないためには、どの値が十分でしょうか?この問題を永久に回避する方法はありますか(たとえば、JRockitのように別のVMを使用)

27
MaVRoSCy

これは複数の再デプロイ後に発生するため、一般的な permgen leak である classloader leak に遭遇したようです。

これらの素敵な獣は、コンテナが所有するオブジェクトから、アプリケーションクラスローダーからロードされたクラスのインスタンスであるオブジェクトへの通常の(弱いではない)参照のために発生します。これらの参照がアンデプロイ時にクリアされない場合、アプリケーションのクラスローダーへの強力な参照チェーンが残っているため、GCできず、ロードされたクラスを解放できません。

一般的な原因は、アプリケーションクラスへの非静的参照が追加されたコンテナクラスの静的コレクションです。

JBoss AS 7は、クラスローダーのリークを防ぐためにモジュールシステムにかなり強力なプロビジョニングを備えているため、なんとかトリガーできたことに驚いています。 GlassfishからAS7に移行して以来、クラスローダーリークは見ていません。

MaxPermSizeを増やすことである程度の時間を節約できますが、問題を取り除くことはできません。

クラスローダーがリークしている理由を本当に解決する必要があります。これを行うのは「楽しい」です。税金、断続的な障害、シャワーの掃除を楽しんでいますよね?リークの追跡を開始できるブログについては、最初のパーのリンクを参照してください。基本的に、アプリクラスローダーへの参照のためにDigに VisualVM および [〜#〜] oql [〜#〜] を使用するか、ヒープダンプを取得して、 jhat (JDKの一部)を使用して、参照を検索します。いずれにせよ、アイデアは、アプリクラスのインスタンスを介してアプリサーバーからクラスローダーへの強力な参照チェーンがどこにあるかを把握することです。

または、アプリのコピーを取得し、リークがなくなるまでビットのリッピングを開始すると役立ちます。 VisualVMまたは他の監視をアプリサーバーに接続して、リークがあるかどうかを確認できますVMおよびPermGenが2回以上のデプロイ/アンデプロイサイクル後に増加するかどうかを確認します。デプロイ/アンデプロイサイクルの自動化を検討してください。リークの原因をアプリの一部および/またはその依存関係の1つに絞り込んで、自己完結型の小さなテストケースを作成し、(a)JBoss AS 7のバグレポートとして提出します。 (b)参照を保持している犯人を防ぐためです。

原因をデプロイメントアーカイブ内にバンドルされている依存関係に絞り込んだ場合、JBoss AS 7モジュールに移動することで問題を解決できます。 JBossモジュールを作成し、AS7のmodulesディレクトリにデプロイし、Manifest.MFまたはjboss-deployment-structure.xmlを介してデプロイメントへの依存関係を追加します。 AS7クラスローダーに関するドキュメント を参照してください。

これが、Project Jigsawが延期されたという事実が私を悲しませている理由です。 Javaneedsこの粗悪品を取り除く強力なモジュールシステム。

56
Craig Ringer

VMパラメーターは次のとおりです。

-XX:MaxPermSize=256M

制限に達しないように十分大きくしてください。

大まかに言って、perm genメモリは、クラスおよびインターンされた文字列に関連付けられたオブジェクトに使用されます。多くの異なるクラスを使用している場合を除き、実行しないでください。

8
Bohemian

まったく同じことをする必要がありましたが、残念ながらvisualvmはあまり役に立ちませんでした。

最終的に、Eclipseマットを使用して、クラッシュ時に生成されたヒープダンプを分析し、leak suspects漏れているModuleClassLoaderインスタンスがたくさんあることを教えてくれたレポート。

概要タブでいずれかのインスタンスをクリックし、merge shortest paths to GC roots + exclude weak referencesは、これらのModuleClassLoaderインスタンスのGCを許可していない犯人を教えてくれました!

https://smalldata.tech/blog/2015/09/29/detecting-Java-permgen-memory-leak

4
Victor Parmar

なぜ起こるのですか?

「PermGen」エラーは、Java仮想マシンが永続世代のメモリを使い果たすと発生します。Javaには4つの世代のガベージコレクタがあります。世代:eden、young、old、permanent。eden世代では、オブジェクトは非常に短命であり、ガベージコレクションはSwiftおよび多くの場合。若い世代はeden世代を生き残ったオブジェクトで構成されます(または割り当て時にeden世代がいっぱいだったため若い世代にプッシュされました)、若い世代のガベージコレクションはそれほど頻繁ではありませんが、かなり定期的な間隔で発生します(アプリケーションが実際に何かを実行し、オブジェクトを時々割り当てている場合)古い世代、まあ、あなたはそれを理解しました。若い世代を生き延びた、または押し下げられたオブジェクトが含まれており、ガベージコレクションはそれほど頻繁ではありませんが、まだ発生する可能性があります。仮想マシンが決定しましたd永遠の命を支持する-これはまさに問題の核心です。永久世代のオブジェクトはガベージコレクションされません。つまり、通常の状況では、jvmが通常のコマンドラインパラメーターで起動されます。したがって、Webアプリケーションを再デプロイすると、WARファイルが解凍され、そのクラスファイルがjvmにロードされます。そして、ここにあります:ほとんどの場合、永久世代になります...(から取得: http://rlogiacco.blogspot.com/2009/02/jboss-and-permgen-outofmemoryerror.html

ここにいくつかのアドバイスがあります:

jVMにこのパラメーターを使用します。これらは、ガベージコレクターにPermGenでもアルゴリズムを呼び出すように指示します。

set Java_OPTS=-Xms512m -Xmx1024m 
-XX:PermSize=512m 
-XX:MaxPermSize=1024m 
-XX:+UseConcMarkSweepGC 
-XX:+CMSPermGenSweepingEnabled 
-XX:+CMSClassUnloadingEnabled 
  • CMSPermGenSweepingEnabled設定には、ガベージコレクションの実行にPermGenが含まれます。デフォルトでは、PermGenスペースはガベージコレクションに含まれることはありません(したがって、無限に成長します)。
  • CMSClassUnloadingEnabled設定は、PermGenガベージコレクションスイープにクラスオブジェクトに対してアクションを実行するように指示します。デフォルトでは、ガベージコレクション中にPermGenスペースにアクセスしている場合でも、クラスオブジェクトは免除されます。

アプリケーションをデプロイするたびにPermGenのデータ量が増えるため、JBOSSを再起動します。

Sun JVMの代わりにJRocket JVMを使用することもできます。ガベージコレクターアルゴリズムにはPermGenがありません。

1
Kamal SABBAR