深入理解JVM(四):类的卸载

github地址:
https://github.com/lishanglei/jvm_study.git

当一个类被加载、验证、准备、解析、初始化后,它的声明周期就开始了。当该类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,该类再方法去的数据也会被卸载,从而结束该类的生命周期。

一个类合适结束生命周期,取决于代表它的Class对象何时结束生命周期

由java虚拟机自带的类加载器(跟加载器bootstrap、扩展类加载器extension、系统加载器system)所加载的类,在虚拟机的生命周期中,始终不会被卸载。java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用他们所加载的类的Class对象,因此这些Class对象始终是可触及的

用户自定义的类加载器所加载的类是可以被卸载的

用户自定义类加载器loader1加载MyTest1类,在类加载器的内部实现中,用一个java集合来存放所加载类的引用。另一方面,一个Class对象总是会引用它的类加载器,调用Class对象的getClassLoader()方法,就能获取它的类加载器。由此可见,MyTest1类的Class实例和loader1之间为双向关联关系

一个类的实例总是引用代表这个类的Class对象。在Object类中定义了getClass()方法,这个方法返回代表对象所属类的Class对象的引用。此外,所有的Java类都有一个静态属性class,它引用代表这个类的Class对象

public class MyTest16_1 extends ClassLoader{


    private String classLoaderName;

    private final String fileExtension = ".class";

    //加载类的路径
    private String path;

    public void setPath(String path) {
        this.path = path;
    }

    /**
     * @param classLoaderName 类加载器的名字
     *                        <p>
     * Creates a new class loader using the <tt>ClassLoader</tt> returned by
     * the method {@link #getSystemClassLoader()
     * <tt>getSystemClassLoader()</tt>} as the parent class loader.
     */
    public MyTest16_1(String classLoaderName) {

        //将系统类加载器当作该类加载器的父类加载器
        super();
        this.classLoaderName = classLoaderName;
    }

    public MyTest16_1(ClassLoader parentClassLoader, String classLoaderName) {
        //显示指定该类加载器的父类加载器
        super(parentClassLoader);
        this.classLoaderName = classLoaderName;
    }

    /**
     * 根据二进制的类的名字查找类,并返回其Class对象
     *
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String className) throws ClassNotFoundException {
        System.out.println("findClass invoked");
        byte[] data = this.loadClassData(className);

        //将字节数组转化为类的Class对象
        return this.defineClass(className, data, 0, data.length);
    }

    /**
     * 根据类的名字返回类数据的字节数组
     *
     * @param clasaName
     * @return
     */
    private byte[] loadClassData(String clasaName) {

        System.out.println("loadClassData invoked");
        InputStream in = null;
        byte[] data = null;
        ByteArrayOutputStream baos = null;
        clasaName = clasaName.replace(".", "\\");

        try {
            in = new FileInputStream(new File(this.path + clasaName + this.fileExtension));
            baos = new ByteArrayOutputStream();
            int ch = 0;
            while (-1 != (ch = in.read())) {
                baos.write(ch);
            }

            data = baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return data;
    }


    @Override
    public String toString() {
        return "[ " + this.classLoaderName + " ]";
    }


    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        MyTest16_1 loader1 = new MyTest16_1("loader1");
        //loader1.setPath("D:\\mingbyte\\jvm_study\\target\\classes");
        loader1.setPath("C:\\Users\\10025\\Desktop\\");
        Class<?> aClass = loader1.loadClass("com.jvm.class_loader.MyTest1");

        //根据类的Class对象生成一个实例
        Object o = aClass.newInstance();
        System.out.println("o 的类加载器: " + o.getClass().getClassLoader());

        loader1=null;
        aClass=null;
        o=null;
        System.gc();


        //将loader1的引用指向一个新的对象
        loader1 =new MyTest16_1("loader2");
        loader1.setPath("C:\\Users\\10025\\Desktop\\");
        Class<?> clazz = loader1.loadClass("com.jvm.class_loader.MyTest1");
        //根据类的Class对象生成一个实例
        Object o1 = clazz.newInstance();
        System.out.println("o1 的类加载器: " + o1.getClass().getClassLoader());


    }
}

输出结果:

findClass invoked
loadClassData invoked
o 的类加载器: [ loader1 ]

[Unloading class com.jvm.class_loader.MyTest1 0x00000007c0061028]

findClass invoked
loadClassData invoked
o1 的类加载器: [ loader2 ]

结果分析:

在JVM命令中添加指令 -XX:+TraceClassUnloading 将类卸载信息打印出来

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值