186

デスクトップ アプリケーションが、通信する必要がある AppServer から動的にクラスのロードを開始できるように、カスタム クラス ローダーがあります。これを行うために必要な瓶の量がばかげているため、これを行いました(出荷したい場合)。実行時に AppServer ライブラリから動的にクラスをロードしないと、バージョンの問題も発生します。

今、私は 2 つの異なる AppServer と通信する必要があるという問題に遭遇し、最初にロードしたクラスによってはひどく壊れる可能性があることがわかりました.JVM を実際に強制終了せずにクラスのアンロードを強制する方法はありますか?

これが理にかなっていることを願っています

4

7 に答える 7

199

クラスをアンロードできる唯一の方法は、使用されているクラスローダーがガベージ コレクションされている場合です。つまり、すべての単一クラスへの参照とクラスローダー自体への参照は、ドードーの道をたどる必要があります。

問題の解決策の 1 つは、すべての jar ファイルにクラスローダーを用意し、クラスの実際のロードを特定の Jar クラスローダーに委譲する各 AppServer にクラスローダーを用意することです。そうすれば、アプリケーション サーバーごとに異なるバージョンの jar ファイルを指定できます。

ただし、これは簡単なことではありません。各バンドルには異なるクラスローダーがあり、依存関係はプラットフォームによって解決されるため、OSGi プラットフォームはまさにこれを行うよう努めています。たぶん、それを見てみるのが良い解決策になるでしょう。

OSGI を使用したくない場合、可能な実装の 1 つは、JAR ファイルごとにJarClassloaderクラスの 1 つのインスタンスを使用することです。

そして、Classloader を拡張する新しい MultiClassloader クラスを作成します。このクラスは内部的に JarClassloader の配列 (またはリスト) を持ち、defineClass() メソッドでは、定義が見つかるまで、または NoClassDefFoundException がスローされるまで、すべての内部クラスローダーを反復処理します。新しい JarClassloader をクラスに追加するために、いくつかのアクセサ メソッドを提供できます。ネット上には MultiClassLoader の可能な実装がいくつかあるため、独自のものを作成する必要さえないかもしれません。

サーバーへの接続ごとに MultiClassloader をインスタンス化すると、原則として、すべてのサーバーが同じクラスの異なるバージョンを使用する可能性があります。

私はプロジェクトで MultiClassloader のアイデアを使用しました。このプロジェクトでは、ユーザー定義のスクリプトを含むクラスをメモリからロードおよびアンロードする必要があり、非常にうまく機能しました。

于 2008-09-29T13:46:52.463 に答える
47

はい、クラスをロードして後で「アンロード」する方法があります。秘訣は、高レベルのクラス ローダー (システム クラス ローダー) とアプリ サーバーのクラス ローダーの間に存在する独自のクラスローダーを実装し、アプリ サーバーのクラス ローダーがクラスの読み込みを上位のローダーに委譲することを期待することです。 .

クラスは、そのパッケージ、その名前、および最初にロードされたクラス ローダーによって定義されます。JVM の起動時に最初にロードされる「プロキシ」クラスローダーをプログラムします。ワークフロー:

  • プログラムが開始し、このプロキシ クラスローダによって実際の「メイン」クラスがロードされます。
  • その後、通常ロードされるすべてのクラス (つまり、階層を壊す可能性のある別のクラスローダーの実装を経由しない) は、このクラスローダーに委譲されます。
  • プロキシ クラスローダは、システム クラスローダに委譲java.xsun.xます (これらは、システム クラスローダ以外のクラスローダを介してロードしてはなりません)。
  • 置き換え可能なすべてのクラスについて、クラスローダをインスタンス化し (クラスを実際にロードし、親クラスローダに委譲しません)、これを介してロードします。
  • クラスのパッケージ/名前をキーとして、クラスローダーを値としてデータ構造 (つまりハッシュマップ) に保存します。
  • プロキシ クラスローダーは、以前にロードされたクラスの要求を取得するたびに、以前に格納されたクラス ローダーからクラスを返します。
  • クラスローダーでクラスのバイト配列を見つけて(またはデータ構造からキーと値のペアを「削除」して)、クラスを変更したい場合はクラスをリロードするだけで十分です。

ClassCastExceptionLinkageErrorなどは発生しません。

クラスローダー階層の詳細については (そうです、まさにあなたがここで実装しているものです;-) Ted Neward による「Server-Based Java Programming」を見てください。

于 2008-09-29T13:59:35.413 に答える
17

クラスローダーを GC せずに個々のクラスをアンロードできるカスタム クラスローダーを作成しました。Jar クラスローダー

于 2010-07-06T15:33:22.387 に答える
12

クラスローダーは厄介な問題になる可能性があります。複数のクラスローダーを使用していて、それらの相互作用が明確かつ厳密に定義されていない場合、特に問題が発生する可能性があります。実際にクラスをアンロードできるようにするには、アンロードしようとしているクラス (およびそのインスタンス) へのすべての参照を削除する必要があると思います。

この種のことを行う必要があるほとんどの人は、OSGiを使用することになります。OSGi は本当に強力で驚くほど軽量で使いやすく、

于 2008-09-29T13:46:13.777 に答える
7

ClassLoader をアンロードできますが、特定のクラスをアンロードすることはできません。より具体的には、自分の管理下にない ClassLoader で作成されたクラスをアンロードすることはできません。

可能であれば、独自の ClassLoader を使用してアンロードできるようにすることをお勧めします。

于 2008-09-29T13:44:39.503 に答える
4

クラスには ClassLoader インスタンスへの暗黙的な強い参照があり、その逆もあります。これらは、Java オブジェクトと同様にガベージ コレクションされます。ツール インターフェイスなどにアクセスしない限り、個々のクラスを削除することはできません。

いつものように、メモリリークが発生する可能性があります。クラスまたはクラスローダーのいずれかへの強い参照は、すべてをリークします。これは、たとえば、ThreadLocal、java.sql.DriverManager、および java.beans の Sun 実装で発生します。

于 2008-09-29T15:19:31.460 に答える