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

来源:互联网 发布:centos系统备份 编辑:程序博客网 时间:2024/05/03 10:22

对于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 0
原创粉丝点击