Java classloader dilemma and locked jar

I was playing with classloaders in Java and noticed a strange thing If the classloader loads a class from a jar, even if you do not reference your classloader, the jar will be locked indefinitely

In the following example, jar contains a class named HelloWorld What I do is try to load the class contained in the jar through the classloader, which adds the jar dynamically If skip is set to true and class is not called Forname, you can delete the jar, but if you don't skip, you can't delete the jar even if you don't reference classloader (classloader = null) until the JVM exits

Why?

PS: I use Java 6, and the code is very verbose for testing purposes

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,len);
            }
            finput.close();
            foutput.close();
            return true;
        }
    }

    public boolean deleteJar() {
        File destJar = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
        return destJar.delete();
    }

}

Solution

I found the answer and the solution

Based on this article and this amazing related article, use class Forname (classname, classloader) is a bad habit because it caches classes in memory indefinitely

The solution is to use classloader Loadclass (clasname), and then when finished, dereference classloader and call the garbage collector with the following command:

classLoader = null;
System.gc();

I hope it helps others!

The above is the whole content of Java classloader dilemma and locked jar collected and sorted by programming home for you. I hope this article can help you solve the program development problems encountered by Java classloader dilemma and locked jar.

If you think the content of the programming home website is good, you are welcome to recommend the programming home website to programmers and friends.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>