CPU使用率が制限に達し、JBossが再起動を必要とするこのエラーが発生しました(Java.lang.OutOfMemoryError: PermGen space
)。
MaxPermSize
を増やす古いJBossバージョンのソリューションを見つけました。 JBoss7についても同じことが言えます。
再び問題に直面しないためには、どの値が十分でしょうか?この問題を永久に回避する方法はありますか(たとえば、JRockitのように別のVMを使用)
これは複数の再デプロイ後に発生するため、一般的な 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この粗悪品を取り除く強力なモジュールシステム。
VMパラメーターは次のとおりです。
-XX:MaxPermSize=256M
制限に達しないように十分大きくしてください。
大まかに言って、perm genメモリは、クラスおよびインターンされた文字列に関連付けられたオブジェクトに使用されます。多くの異なるクラスを使用している場合を除き、実行しないでください。
まったく同じことをする必要がありましたが、残念ながら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
なぜ起こるのですか?
「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
アプリケーションをデプロイするたびにPermGenのデータ量が増えるため、JBOSSを再起動します。
Sun JVMの代わりにJRocket JVMを使用することもできます。ガベージコレクターアルゴリズムにはPermGenがありません。