Java で classLoaders をいじっていて、奇妙なことに気付きました。classLoader が jar からクラスをロードする場合、classLoader の参照を解除しても、この jar は無期限にロックされます。
以下の例では、jar に HelloWorld というクラスが含まれています。私がしていることは、jar を動的に追加する classLoader を介して、jar に含まれるクラスをロードしようとすることです。に設定skip
してtrue
呼び出さないClass.forName
場合は jar を削除できますが、スキップせずにclassLoader
( classLoader = null
) を参照解除しても、JVM が終了するまで jar を削除できません。
何故ですか?
PS: 私は Java 6 を使用しており、コードはテスト目的で非常に冗長です。
package loader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class TestClassLoader {
private URLClassLoader classLoader;
public TestClassLoader() throws MalformedURLException, IOException {
System.out.println("Copying jar");
if (copyJar()) {
System.out.println("Copying SUCCESS");
performFirstCheck();
} else {
System.out.println("Copying FAILED");
}
}
public static void main(String[] args) throws IOException {
System.out.println("Test started");
TestClassLoader testClassLoader = new TestClassLoader();
System.out.println("Bye!");
}
public void performFirstCheck() throws IOException {
System.out.println("Checking class HelloWorld does not exist");
if (!checkClassFound(TestClassLoader.class.getClassLoader(), false)) {
System.out.println("Deleting jar");
deleteJar();
System.out.println("First Check SUCCESS");
performSecondCheck();
} else {
System.out.println("First Check FAILED");
}
}
private void performSecondCheck() throws IOException {
System.out.println("Copying jar");
if (copyJar()) {
System.out.println("Copying SUCCESS");
createClassLoaderAndCheck();
} else {
System.out.println("Copying FAILED");
}
}
private void createClassLoaderAndCheck() throws MalformedURLException {
System.out.println("Creating classLoader");
createClassLoader();
System.out.println("Checking class HelloWorld exist");
if (checkClassFound(classLoader, true)) {
System.out.println("Second Check SUCCESS");
classLoader = null;
System.out.println("Deleting jar");
if (deleteJar()) {
System.out.println("Deleting SUCCESS");
} else {
System.out.println("Deleting FAILED");
}
} else {
System.out.println("Second Check FAILED");
}
}
public void createClassLoader() throws MalformedURLException {
URL[] urls = new URL[1];
File classFile = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
urls[0] = classFile.toURI().toURL();
classLoader = new URLClassLoader(urls);
}
public boolean checkClassFound(ClassLoader classLoader, boolean skip) {
if (skip) {
System.out.println("Skiping class loading");
return true;
} else {
try {
Class.forName("HelloWorld", true, classLoader);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
public URLClassLoader getClassLoader() {
return classLoader;
}
public boolean copyJar() throws IOException {
File sourceJar = new File("C:\\Users\\Adel\\Desktop\\Folder\\classes.jar");
File destJar = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
if (destJar.exists()) {
return false;
} else {
FileInputStream finput = new FileInputStream(sourceJar);
FileOutputStream foutput = new FileOutputStream(destJar);
byte[] buf = new byte[1024];
int len;
while ((len = finput.read(buf)) > 0) {
foutput.write(buf, 0, len);
}
finput.close();
foutput.close();
return true;
}
}
public boolean deleteJar() {
File destJar = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
return destJar.delete();
}
}