深入JVM原理之类加载 - 双亲委派模型
一、类加载机制
-
类加载机制:虚拟机把描述类的数据从.class文件加载到内存中,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
-
类加载的过程:
(1) 加载:将class文件字节码内容加载到内存中;并将这些内容转换成方法区中的运行时数据结构;在内存中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口在方法区中分配
(2) 验证:确保class 文件中的字节内容符合jvm规范,并且不会危害jvm自身的安全
(3) 准备:正式为类变量(静态变量)分配内存空间,并为静态变量初始化(赋默认值),静态变量的内存
(4) 解析:虚拟机常量池内的符号引用替换为直接引用的过程,比如String s =“aaa”,转化为 s的地址指向“aaa”的地址
(5) 初始化:根据程序员通过程序制定的主观计划完成静态变量等资源的初始化。在这个过程会完成静态变量的赋值和静态代码块中的语句
二、类加载器(ClassLoader)
-
类加载器:用于实现类加载过程中加载阶段,负责将class文件字节码内容加载到内存中;并将这些内容转换成方法区中的运行时数据结构,在内存中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
-
类加载器的分类:
(1) 虚拟机自带的类加载
a. 启动类加载器:C++语言实现,负责加载 %Java_home%/jre/lib/rt.jar 中的内容
b. 扩展类加载器:Java语言实现,负责加载%Java_home%/jre/lib/ext/*.jar中的内容
c. 应用程序类加载器:也可以称为系统类加载器,它负责加载用户类路径classPath的所有类。
注意:如果应用程序中没有定义过自己的类加载器,一般情况默认使用应用程序类加载
(2) 用户自定义的类加载器:
a. 用户可以自定义类加载器,继承java.lang.ClassLoader -
类加载器的双亲委派模型(Parents Delegation Model):
工作过程:如果一个类加载器收到了加载请求,它首先不会尝试使用自己加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载中,只有父类反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需要的类)的时候,子类才会尝试自己加载。
好处:采用双亲委派模型组织累加器之间的关系,有一个显而易见的好处是Java随着它的类加载一起具备了一种带有优先级的层次关系,例如加载位于rt.jar中的java.lang.Object类,无论哪一个类加载加载这个类,最终都委托给最*的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。
-
示例代码:
public class Test{ public static void main(String[] args) throws IOException { Object obj = new Object(); System.out.println(obj.getClass().getClassLoader()); MyClass mc = new MyClass(); System.out.println(mc.getClass().getClassLoader(). getParent().getParent()); System.out.println(mc.getClass().getClassLoader().getParent()); System.out.println(mc.getClass().getClassLoader()); } } class MyClass{}
-
类加载器底层分析:
双亲委派模型对于java正常运作很重要,但是底层实现非常简单,实现双亲委派的大代码集中在java.lang.ClassLoader的loadClass()方法中:先检查是否已经被加载过,若没有加载则调用父类的loadClass方法,直到找到启动类加载,启动类加载器在在自己的范围内进行搜素,如果父类加载器加载失败,则子类处理异常,调用自身的findClass方法进行加载。
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // If still not found, then invoke findClass in order // to find the class. c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } private Class findBootstrapClass0(String name) throws ClassNotFoundException{ check(); if (!checkName(name)) throw new ClassNotFoundException(name); return findBootstrapClass(name); } private native Class findBootstrapClass(String name)throws ClassNotFoundException;
下一篇: MySQL调优(四)查询优化