質問
カスタムクラスローダーがあるため、デスクトップアプリケーションは、対話する必要があるAppServerからクラスのロードを動的に開始できます。これを行うのに必要な瓶の量はばかげているので(これを出荷したい場合)、これを行いました。また、実行時にAppServerライブラリからクラスを動的にロードしないと、バージョンの問題が発生します。
今、2つの異なるAppServerと通信する必要があるという問題が発生しました。最初にロードするクラスによっては、ひどく壊れる可能性があります...実際に強制終了せずにクラスのアンロードを強制する方法はありますかJVM?
これが理にかなっていることを願って
解決
クラスをアンロードできる唯一の方法は、使用するクラスローダーがガベージコレクションされている場合です。つまり、すべてのクラスとクラスローダー自体への参照は、dodoの方法で行う必要があります。
あなたの問題の1つの可能な解決策は、すべてのjarファイルにクラスローダーを持ち、特定のJarクラスローダーにクラスの実際のロードを委任するAppServerのそれぞれにクラスローダーを持つことです。そうすれば、すべてのAppサーバーに対して異なるバージョンのjarファイルを指定できます。
しかし、これは簡単なことではありません。 OSGiプラットフォームは、各バンドルに異なるクラスローダーがあり、プラットフォームによって依存関係が解決されるため、まさにこれを実行しようとします。たぶん良い解決策はそれを見てみることでしょう。
OSGIを使用したくない場合、可能な実装の1つは、 JarClassloader クラス。
そして、Classloaderを拡張する新しいMultiClassloaderクラスを作成します。このクラスは内部的にJarClassloaderの配列(またはリスト)を持ち、defineClass()メソッドでは、定義が見つかるか、NoClassDefFoundExceptionがスローされるまで、すべての内部クラスローダーを繰り返し処理します。クラスに新しいJarClassloaderを追加するために、いくつかのアクセサーメソッドを提供できます。 MultiClassLoaderのネット上にはいくつかの実装が考えられるため、独自に作成する必要さえないかもしれません。
サーバーへの接続ごとにMultiClassloaderをインスタンス化する場合、原則としてすべてのサーバーが同じクラスの異なるバージョンを使用する可能性があります。
プロジェクトでMultiClassloaderのアイデアを使用しました。ユーザー定義スクリプトを含むクラスをメモリからロードおよびアンロードする必要があり、非常にうまく機能しました。
他のヒント
はい、クラスをロードして「アンロード」する方法があります。それらは後で。トリックは、高レベルのクラスローダー(システムクラスローダー)とアプリサーバーのクラスローダーの間に存在する独自のクラスローダーを実装し、アプリサーバーのクラスローダーがクラスローディングを上位ローダーに委任することを期待することです。 。
クラスは、パッケージ、名前、および最初にロードしたクラスローダーによって定義されます。 「プロキシ」をプログラムするJVMの起動時に最初にロードされるクラスローダー。ワークフロー:
- プログラムが起動し、実際の「メイン」クラスがこのプロキシクラスローダーによってロードされます。
- 通常ロードされるすべてのクラス(つまり、階層を壊す可能性のある別のクラスローダー実装を介さない)は、このクラスローダーに委任されます。
- プロキシクラスローダーは、
java.x
およびsun.x
をシステムクラスローダーに委任します(これらは システムクラスローダー)。 - 交換可能なすべてのクラスについて、クラスローダー(実際にクラスをロードし、親クラスローダーに委任しない)をインスタンス化し、これを介してロードします。
- クラスのパッケージ/名前をキーとして、クラスローダーを値としてデータ構造(つまり、ハッシュマップ)に保存します。
- プロキシクラスローダーは、以前にロードされたクラスのリクエストを取得するたびに、以前に保存されたクラスローダーからクラスを返します。
- クラスローダーによってクラスのバイト配列を特定し(またはデータ構造からキーと値のペアを「削除」し)、変更する場合にクラスをリロードするだけで十分です。 li>
完了したら、 ClassCastException が発生しないはずですまたは LinkageError など
>クラスローダー階層の詳細については(はい、ここで実装しているものです;-) &quotをご覧ください。 ;サーバーベースのJavaプログラミング"テッド・ニューアード-この本は、あなたが望むものに非常に似たものを実装するのに役立ちました。
カスタムクラスローダーを作成しました。このクラスローダーから、クラスローダーをGCせずに個々のクラスをアンロードできます。 ジャークラスローダー
クラスローダーは厄介な問題になる可能性があります。複数のクラスローダーを使用しており、それらの相互作用が明確かつ厳密に定義されていない場合、特に問題が発生する可能性があります。実際にクラスをアンロードできるようにするには、アンロードしようとしているクラス(およびそのインスタンス)へのすべての参照を削除する必要があります。
この種のことを行う必要があるほとんどの人は、 OSGi を使用することになります。 OSGiは本当に強力で、驚くほど軽量で使いやすい、
ClassLoaderはアンロードできますが、特定のクラスをアンロードすることはできません。具体的には、管理下にないClassLoaderで作成されたクラスをアンロードすることはできません。
可能であれば、アンロードできるように独自のClassLoaderを使用することをお勧めします。
クラスには、ClassLoaderインスタンスへの暗黙の強い参照があり、その逆も同様です。これらは、Javaオブジェクトと同様にガベージコレクションされます。ツールインターフェースなどを使用しないと、個々のクラスを削除できません。
これまでどおり、メモリリークが発生する可能性があります。クラスまたはクラスローダーのいずれかへの強い参照は、すべてをリークします。これは、SunのThreadLocal、java.sql.DriverManager、java.beansなどの実装で発生します。
JConsole など、クラスのアンロードロジックの最後に java.lang.System.gc()
を追加してみてください。ガベージコレクターを明示的にトリガーします。