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