深入理解JVM(五)-Java类加载器

对于C/C++开发者来说,他们在内存管理方面具有至高的权利,但是也承担着巨大的维护责任。而对于Java程序员来说,有了JVM(Java虚拟机)管理机制的帮助,再也不用担心内存泄漏和内存溢出问题了。因此,这篇文章我将深入探讨一下JVM,它的内部结构以及运行原理。

Java中的类加载器

这里写图片描述

  • 启动(Bootstrap)类加载器:引导类装入器是用本地代码实现的类装入器,它负责将 < Java_Runtime_Home>/lib 下面的类库加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。注意:启动加载器用C++实现,是虚拟机自身的一部分。

  • 标准扩展(Extension)类加载器:扩展类加载器是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader) 实现的。它负责将 < Java_Runtime_Home >/lib/ext 或者由系统变量 java.ext.dir 指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。

  • 系统(System)类加载器:系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。

  • 自定义的类加载器:
    要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用。

protected Class< ?> findClass(String name)
throws ClassNotFoundException

参数:
name - 类的二进制名称

返回:
得到的 Class 对象

抛出:
ClassNotFoundException - 如果无法找到类

双亲委派模型

双亲委派的过程:当一个类加载器收到了类加载的请求,它首先不会自己尝试去加载类,而是将这个类委派给父类加载器去加载,这样一层层向上递进,只有在父类加载器都反馈加载不了的时候,子加载器才尝试自己去加载。

使用双亲委派机制的一个好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,另外保证Java中类的加载都使用唯一的类加载器加载,保证内存里只会加载一份system字节码。

Java双亲委派模型对保证Java的稳定运行很重要,但是它的实现却很简单,实现的代码都在 java.lang.ClassLoader 的loadClass()方法中。

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先检查请求的类是否已经被加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // 如果父类加载器抛出ClassNotFoundException 
                    // 说明父类加载器无法完成加载请求
                }

                if (c == null) {
                    // 父类加载器无法加载之后
                    // 调用自身的findClass方法
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

先检查是否已经被加载过,若没有加载则调用父类的loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器。若父加载器加载失败,抛出 ClassNotFoundException 异常后,再调用自己的findClass()方法进行加载。

注意:Java双亲委派机制并不是一个强制性的约束模型,而是Java设计者们推荐给大家的类加载器的实现方式。

感谢

如果大家想了解更多,欢迎继续阅读接下来的章节,推荐大家熟读《深入理解Java虚拟机》这本书。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值