7

GlassfishV2.1.1で実行されている複雑なアプリケーションがあります。コードを動的にロードできるようにするために、クラスを再定義できるCustomClassloaderを実装しました。動作は非常に簡単です。動的にロードされたクラスが変更されると、CustomClassloaderの現在のインスタンスが「ドロップ」され、必要なクラスを再定義するために新しいインスタンスが作成されます。

これは、同じクラスが数回リロードされた後(したがって、新しいCustomClassloaderが作成されるたびに)、CustomClassloaderの他のインスタンスがガベージコレクションされないため、PermGenスペースエラーが発生することを除いて、うまく機能します。(このクラスのインスタンスは1つだけである必要があります)

リークがどこにあるかを追跡するために、さまざまな方法を試しました。

  1. visualvm =>ヒープダンプを作成し、CustomClassloaderのすべてのインスタンスを抽出します。いずれも確定していないことがわかります。最も近いGCルートを確認すると、visualvmは存在しないことを通知します(最後のインスタンスを除いて、これは「実際に使用された」ものであるため)。
  2. jmap / jhat =>ほぼ同じ結果が得られます。CustomClassloaderのすべてのインスタンスが表示され、リンクをクリックしてそのうちの1つの参照がどこにあるかを確認すると、何もないことを意味する空白のページが表示されます。 。
  3. Eclipse Memory Analyzer Tool =>次のOQLクエリを実行すると、奇妙な結果が得られます。 結果が1つしかないため、明らかに正しくないSELECT c FROM INSTANCEOF my.package.CustomClassloader c インスタンスが1つしかないことを示しています。

また、このリンクを確認し、新しいCustomClassloaderが作成されたときにいくつかのリソースリリースを実装しましたが、何も変わりません。PermGenメモリはまだ増え続けています。

ですから、おそらく何かが足りないのですが、ポイント(1-2)と(3)の違いは、私が理解できないことを示しています。何が悪いのかを知るためにどこを見ればいいですか?私が従ったすべてのチュートリアルは、「最も近いGCルートの検索」機能を使用してリークしている参照を検索する方法を示しているため(私の場合はありません)、エラーを追跡する方法がわかりません。

編集1:ヒープダンプの例をここにアップロードしました。アンロードされていないClassLoaderは、次のクエリを使用してvisualvmで選択できますselect s from saierp.core.framework.system.SAITaskClassLoader s 。GCルートがないため、4つのインスタンスがあり、最初の3つが収集されていることがわかります...どこかに参照があるはずですが、私はしません。どうすれば検索できるかわかりません。どんなヒントも歓迎します:)

編集2:いくつかのより深いテストの後、私は非常に奇妙なパターンを見る。リークは、OpenJPAによってロードされているデータに依存しているようです。新しいデータがロードされていない場合は、クラスローダーをGCできますが、そうでない場合はそうではありません。新しいSAITaskClassLoaderを作成して古いものを「クリア」するときに使用するコードは次のとおりです。

PCRegistry.deRegister(cl);
LogFactory.release(cl);
ResourceBundle.clearCache(cl);
Introspector.flushCaches();

=パターン1(クラスローダーはGCされます):=

  1. 新しいSAITaskClassLoader
  2. データのロードD1、D2、...、Dn
  3. 新しいSAITaskClassLoader
  4. データのロードD1、D2、...、Dn
  5. ..。

cl-gc

=パターン2(クラスローダーはGCされていません):=

  1. 新しいSAITaskClassLoader
  2. データのロードD1、D2、D3
  3. 新しいSAITaskClassLoader
  4. データのロードD3、D4、D5
  5. 新しいSAITaskClassLoader
  6. データのロードD5、D6、D7
  7. ..。

cl-nogc

いずれの場合も、クリアされたSAITaskClassLoaderにはGCルートがありません。OpenJPA1.2.1を使用しています。

感謝をこめて

4

3 に答える 3

6

のソースコードのスニペットCustomClassLoaderまたは実際のヒープダンプがないと、問題を追跡するのは非常に困難です。CustomClassLoaderシングルトンになることはできません。もしそうなら、あなたのデザインはうまくいきません(または私は何かを逃しました)。

ClassLoaderタイプのインスタンスのリストを取得し、CustomClassLoaderこれらのオブジェクトへの参照を追跡する必要があります。

これらの投稿は、それをさらに分析し、ClassLoaderリークを追跡するための暗い詳細に入る方法について役立つ可能性があります。

于 2012-12-08T15:55:35.357 に答える
2

クラスローダーのガベージコレクションは、非常にトリッキーなビジネスです。JProfilerを使用すると、現在アクティブなカスタムクラスローダーへの次の着信参照のチェーンが表示されます。

ここに画像の説明を入力してください

これは、クラスローダー自体を参照する静的フィールド「singleInstance」がカスタムクラスローダーにあることを示しています。VMがクラスローダーを収集しやすくするために、再デプロイ時にそのフィールドをクリアするようにしてください。

Eclipse MATで得られた結果に関する注記:強く到達できないすべてのオブジェクトが削除されます。JProfilerもデフォルトでこれを行います。したがって、以前の3つのクラスローダーはガベージコレクションされる必要がありますが、ヒープ内の標準参照によってキャプチャされないクラスローダーGCに対してJVMが持つ特別なルールのため、ガベージコレクションされません。

免責事項:私の会社はJProfilerを開発しています

于 2012-12-10T11:33:56.027 に答える
1

最後に、OpenJPAおよびパラメーター化されていないクエリにリンクされているように見えるため、このバグを閉じることができます。注目すべき別のスレッド:ガベージコレクションされていないカスタムClassLoader

于 2014-12-03T23:21:56.297 に答える