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();
        }
    }
}

v4ki5mqu
1 声望0 粉丝

« 上一篇
java反射
下一篇 »
JMX案例