2011-09-20 18 views
7

ユーザー提供のスクリプトが実行されている間に一時的にコードを表示させるために、アプリケーションに多数のクラスローダーを作成する必要がある場合があります。私はこれにURLClassLoaderを使用しています。ClassLoaderを "閉じる"にはどうすればいいですか?

スクリプトが終了すると、クラスローダーを「アンロード」または「クローズ」してリソースを解放する必要があります。

クラスローダーへの参照をnullに設定するだけで十分ですか?私は特に、余分なクラスがJARファイルにあるので、最終的にファイルハンドルが足りなくなるかどうかは疑問です。

PS:Java 5以上で動作する必要があります。ええ、私は知っている...

+0

これが役に立つかもしれませんします。http:// stackoverflowの。 com/questions/148681/unloading-classes-in-java? – Thomas

+0

オブジェクト参照を削除したり、クラスをアンロードする必要があります。だからあなたは奇妙な、またはpermgenを心配しています – ssedano

+0

実際には、オープンな接続(つまり、リソースを読み込むために開いたInputStreams)が心配です。 –

答えて

4

クラスローダーがロードしたすべてのクラスが参照を持たなくなり、クラスローダー自体への参照がすべて消去された場合、クラスローダーとクラスローダーはグループとしてガベージコレクションされます。

これは、参照されていないクラスをアンロードするJVM属性セットがあるかどうかに依存します。ほとんどの環境ではデフォルトで設定されていますが、一部の組み込みの場合はそうでないかもしれません。

[クラスへの参照を削除するのは簡単なことです。名前でそれを参照する他のクラスは、もちろん削除を防ぎます。 ClassLoader.findClassなどを使用してクラスをロードする必要があります。]

+0

あなたはその属性を知っていますか? – home

+0

いいえ、あまり目立たないものの1つで、後のJVMで外部化することはできません。 –

+0

それはコインの片面です。クラスを含むJARを変更し、新しいクラスローダーを作成し、まったく同じURLを使用してロードすると、新しいクラスが取得されるのでしょうか、それともキャッシュが含まれていますか? –

1

URLクラスローダーまたはその親クラスのいずれにもclose()メソッドがないので、運が悪いです。

GCでこれを処理しないでください。

+0

同意すると、(特にその親からの)ClassLoaderの参照を停止すると、そのクラスが収集され、そのクラスが続きます。 – Guillaume

+0

@Guillaume - 簡単にはできません。 –

3

クラスローダーからクラス(およびオブジェクト)をロードしなくても、そのクラスローダーへの参照を保持しない場合は、ガベージコレクターによって自動的に処理されます。

0

JavaClassLoaderを拡張し、Java 7を基にしたクローズメソッドを作成しました。私はiPad 2でIRCボットを開発したかったので、私は必要なことをやりました。今、私のプラグインシステムはJava 6と7で安定しています。

+4

'close()'メソッドは何をしますか? –

+0

(私はそれがローダーを収集可能にしないと確信しています) –

5

少し遅れていますが、この質問に後で(私のように)来る人にとってはうれしいことです。

Java 7では、URLClassLoaderにclose()メソッドが追加されました。これは、OPが求めていたものです。

EDIT(@Hotリックスのおかげで) OK、それはOPがのために求めているまさに何ではありませんので。すべてのリソースを解放したり、リソースとローダーを収集したりすることはありません。これは単に、クラスローダーを使用してより多くのリソースをロードすることを防ぎます。 ですが、URLClassLoaderでロードされたjarファイルを閉じます。

+0

* close()*メソッドは、ローダーとそのリソースを収集することはできません。 –

+0

ありがとうございます。どのように私はそれを逃したか分からない。しかし、jarファイルを閉じると思われます。つまり、正しく理解すれば、jarファイルを削除/変更できるようになります。 –

+0

はい、jarファイルが閉じられていることを意味します。 –

3

あなたはJava7を使用することはできません、それは(近いなら)方法、使用反射そうのように、クラスローダの開いているすべてのJARアーカイブを閉じるには:

public void close() { 
try { 
    Class clazz = java.net.URLClassLoader.class; 
    java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp"); 
    ucp.setAccessible(true); 
    Object sun_misc_URLClassPath = ucp.get(this); 
    java.lang.reflect.Field loaders = 
     sun_misc_URLClassPath.getClass().getDeclaredField("loaders"); 
    loaders.setAccessible(true); 
    Object java_util_Collection = loaders.get(sun_misc_URLClassPath); 
    for (Object sun_misc_URLClassPath_JarLoader : 
     ((java.util.Collection) java_util_Collection).toArray()) { 
     try { 
     java.lang.reflect.Field loader = 
      sun_misc_URLClassPath_JarLoader.getClass().getDeclaredField("jar"); 
     loader.setAccessible(true); 
     Object java_util_jar_JarFile = 
      loader.get(sun_misc_URLClassPath_JarLoader); 
     ((java.util.jar.JarFile) java_util_jar_JarFile).close(); 
     } catch (Throwable t) { 
     // if we got this far, this is probably not a JAR loader so skip it 
     } 
    } 
} catch (Throwable t) { 
    // probably not a SUN VM 
} 
return; 
} 
+0

私はJava 1.6を使用しています。フルGCでURLClassloaderをクリーンアップしましたが、 'lsof'で表示されたjarファイルのFDが数多く見られました。あなたは私の問題を解決しました! – waltersu

関連する問題