关于java:类卸载

43次阅读

共计 2099 个字符,预计需要花费 6 分钟才能阅读完成。

package study;

import java.net.URL;
import java.net.URLClassLoader;
/*
    由 Java 虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载,Java 虚拟机自带的类加载器包含根类加载器、扩大类加载器和零碎类加载器。Java 虚拟机自身会始终援用这些类加载器,而这些类加载器则会始终援用它们所加载的类的 Class 对象,因而这些 Class 对象始终是可涉及的。由用户自定义的类加载器加载的类是能够被卸载的。jvm 参数 -verbose:class 即可看到类的加载和卸载信息
 */
/*
卸载类满足的条件
    1、class 所有实例被回收
    2、class 类没有别援用
    3、class 的加载器实例被回收
 */
public class StudyMain {public static void main(String[] args) throws Exception {new StudyMain().solve();
        Thread.sleep(5000);
        System.gc();
        Thread.sleep(5000);
    }

    public void solve() {
        /*
         path 不以’/' 结尾时,默认是从此类所在的包下取资源;path 以’/' 结尾时,则是从 ClassPath 根下获取;this.getClass().getResource("").getPath();
         */
        // 这个门路 <= appClassLoader 所负责的门路,因为双亲委托的机制
        String path = "/D:/gitHome/asmStudy/target/classes/";
        try {
            // 这里肯定要加 file: 示意协定
            ClassLoader loader1 = new URLClassLoader(new URL[]{new URL("file:" + path)});
            // 类名要写全
            Class t =  loader1.loadClass("instrumentation.TransClass");
            t = null;
            loader1 = null;
        } catch (Exception e) {e.printStackTrace();
        }
    }
}

当类加载器重写了 finalize

package study;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class MyClassLouder extends ClassLoader {public static void main(String[] args) throws Exception {
        String path = "D:\\Users\\YEZHENGWU839\\Desktop\\xiaoxi\\";
        MyClassLouder other = new MyClassLouder(path, "other");
        Class.forName("MethodAccessor.TestLoad", true, other);
        other = null;
        Thread.sleep(5000);
        System.gc();
        Thread.sleep(5000);
        // 第一次 gc 卸载不掉类是因为 finalize 线程优先级比拟低 所以回收的时候
        // other 的 finalize 对象还没有被 finalize 线程清理
        // 所以 other 并没有回收,所以类也就卸载不了
        System.out.println("第一次 gc 完结 第二次开始");
        System.gc();
        Thread.sleep(5000);
    }

    private String classpath;
    private String name;
    // 重写 finalize 办法 个别不重写这个 影响 gc
    @Override
    protected void finalize() throws Throwable {System.out.println("MyClassLoader finalize");
    }

    public MyClassLouder(String classpath, String name) {
        this.classpath = classpath;
        this.name = name;
    }

    public MyClassLouder(String classpath, String name, ClassLoader parent) {super(parent);
        this.classpath = classpath;
        this.name = name;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
       try {byte[] bin = Files.readAllBytes(Paths.get(classpath + name.replace(".", "/") + ".class"));
            return defineClass(bin, 0, bin.length);
        } catch (IOException e) {throw new ClassNotFoundException();
        }
    }
}

正文完
 0