Java classLoader困境与锁定的罐子
发布时间:2020-12-14 06:06:02 所属栏目:Java 来源:网络整理
导读:我正在玩 Java中的classLoaders并注意到一件奇怪的事情.如果classLoader从jar加载一个类,即使你没有引用你的classLoader,这个jar也会无限期地被锁定. 在下面的示例中,jar包含一个名为HelloWorld的类.我所做的是尝试通过classLoader加载jar中包含的类,该类动
我正在玩
Java中的classLoaders并注意到一件奇怪的事情.如果classLoader从jar加载一个类,即使你没有引用你的classLoader,这个jar也会无限期地被锁定.
在下面的示例中,jar包含一个名为HelloWorld的类.我所做的是尝试通过classLoader加载jar中包含的类,该类动态地添加jar.如果将skip设置为true并且不调用Class.forName,则可以删除jar,但如果不跳过,即使不引用classLoader(classLoader = null),也不能删除jar,直到JVM退出. 这是为什么? 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:UsersAdelDesktopclasses.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:UsersAdelDesktopFolderclasses.jar"); File destJar = new File("C:UsersAdelDesktopclasses.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,len); } finput.close(); foutput.close(); return true; } } public boolean deleteJar() { File destJar = new File("C:UsersAdelDesktopclasses.jar"); return destJar.delete(); } } 解决方法
我找到了答案和解决方法.
基于这个article和这个惊人的相关article,使用Class.forName(className,classLoader)是一个坏习惯,因为它使类无限期地缓存在内存中. 解决方案是使用classLoader.loadClass(clasName),然后完成后,取消引用classLoader并使用以下命令调用垃圾收集器: classLoader = null; System.gc(); 希望这有助于他人! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |