您的位置:首页 > 编程语言 > Java开发

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

2016-03-30 18:47 441 查看
对于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虚拟机》这本书。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: