web-dev-qa-db-ja.com

Javaクラスローダーはいつどのようにガベージコレクション用にマークされますか?

複数の子クラスローダーを作成して、複数のサブアプリケーションをJavaアプリケーション "コンテナー"にロードし、ホットデプロイメントのプロトタイピングを行います。特定のクラスローダーのクラスパスが変更された場合(つまり、jarが追加、削除された場合、更新されました)、古いクラスローダーは破棄され(参照されません)、jarの新しいクラスパス用に新しいクラスローダーが作成されます。

クラスパスを更新し、ホットデプロイメントをトリガーした後、ヒープダンプを取得しました。ヒープダンプ(メモリアナライザを使用)は、古いクラスローダーがガベージコレクションされていなかったことを示します。親クラスローダーの特定のクラスは、古いクラスローダーをキャッシュしていました。これらのキャッシュをクリアするために、次のものが呼び出されました。

Java.lang.ResourceBundle.clearCache(classLoader);
org.Apache.commons.logging.LogFactory.release(classLoader);
Java.beans.Introspector.flushCaches();

上記のキャッシュをクリアした後でも、古いクラスローダーはまだガベージコレクションされていませんでした。クラスローダーへの残りの参照には、次のものが含まれていました。

  • クラスローダーによってロードされたクラス
  • Java.lang.Packageはクラスローダー自体によって作成されます
  • クラスローダー自体によって作成されたJava.lang.ProtectionDomain

上記はすべてクラスローダー内の循環参照であり、ガベージコレクションをトリガーする必要があります。なぜそうではないのかわかりません。循環参照があっても古いクラスローダーがまだガベージコレクションされていない理由を誰かが知っていますか?

44
onejigtwojig

Classloaderのアンロードには問題があるといつも聞いていました。それらは 理論的に オブジェクトインスタンスへの参照がなく、クラスのアンロードが不要な場合に収集されるガベージですが、実際にはもっと問題があるようです。微妙な参照がリークし、Classloaderが再利用されなくなる可能性があります。アプリケーションサーバーでは、何度も再デプロイを繰り返した後、時々OutOfMemoryError: PermGen space

言うまでもなく、どこかにそれが収集されるのを妨げる厄介な参照があると思います-おそらくメモリアナライザはリンクを正しくたどっていませんでした。これらの記事で説明されているように、これはすべて発生する可能性があるようです。

また、あなたが何をしているのか正確にはわかりませんが、JDK 7を待つことができれば、AnonymousClassLoaderを見ることができます。この投稿で説明されているように、動的言語をより適切にサポートするために導入されます。

お役に立てば幸いです。

18
ewernli