gpt4 book ai didi

带有锁定 jar 的 Java classLoader 困境

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:53:33 24 4
gpt4 key购买 nike

我在 Java 中使用类加载器时发现了一件奇怪的事情。如果 classLoader 从 jar 加载类,即使您取消引用 classLoader,这个 jar 也会被无限期锁定。

在下面的示例中,jar 包含一个名为 HelloWorld 的类。我所做的是尝试通过动态添加 jar 的类加载器加载 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();
}

}

最佳答案

我找到了答案和解决方法。

基于此article和这个惊人的相关article ,使用 Class.forName(className, true, classLoader) 是一个坏习惯,因为它会无限期地将类缓存在内存中。

解决方案是改用 classLoader.loadClass(clasName),然后一旦完成,取消引用 classLoader 并使用以下方式调用垃圾收集器:

classLoader = null;
System.gc();

希望这对其他人有帮助! :)

背景信息:

我的项目很复杂:我们有一个 GWT 服务器充当另一个服务器的 RMI 客户端。因此,要创建实例,GWT 需要从服务器下载类并加载它们。稍后,GWT 将重新发送实例到服务器以使用 Hibernate 将它们持久保存在数据库中。为了支持热部署,我们选择了动态类加载,用户可以上传一个 jar 并通知服务器从中加载类并将它们呈现给 GWT 服务器可用

关于带有锁定 jar 的 Java classLoader 困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11273303/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com