JVM之类加载器

JVM之类加载器

 

 

 

类加载器种类

 

  •  启动类加载器(Bootstrap ClassLoader):JVM启动的类加载器,JVM就像一个应用程序,启动时就要靠这个类加载器,相当于JVM的启动器。负责加载$JAVA_HOME/jre/lib/下核心API或者-Xbootclasspath选项指定的jar包,如java.lang.*
  • 扩展加载器(Extension ClassLoader):加载位置 :jre\lib\ext中
  • 系统类加载器(APP ClassLoader):加载ClassPath下的类,也就是我们程序中定义的类
  • 自定义类加载:必须继承ClassLoader,可以加载我们定义的路径

 

 

 

类加载机制

 

    全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。

 

    父类委托:先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。

 

    缓存机制:缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。

 

 

 

 

类加载器使用的模型

 

       双亲委派模型:加载这个类之前,要先加载其父类,父类加载完了,再加载这个类;如果没有父类,就由发起者自行加载,如果子类都加载不了,就会报ClassNotFoundException。

 

好处:防止类重复加载,父类加载了之后,子类就不用通过自己的ClassLoader加载了。

 

 
   
 

 

 

 

主动触发类加载的情况

 

  1. 创建类的实例,也就是new一个对象
  2. 访问某个类或接口的静态变量,或者对该静态变量赋值
  3. 调用类的静态方法
  4. 反射(Class.forName("com.lyj.load"))
  5. 初始化一个类的子类(会首先初始化子类的父类)
  6. JVM启动时标明的启动类,即文件名和类名相同的那个类

 

 

类加载流程

 

JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的java类的全过程。

 

仔细分:包含下面7个步骤,加载、验证、准备、解析、初始化、使用、卸载(其中验证、准备、解析合并为连接)

 

               
加载

 

做了下面三步:

 

  1. 读class文件:通过类名,导入class文件,得到此类的二进制字节流
  2. 将类结构加载到方法区:将静态存储结构转化为方法区运行时数据结构
  3. 生成反射对象:在堆中生成一个该类的class对象(反射对象),作为方法区数据访问的入口

 

 

验证

 

检查class文件的正确性,如不正确会抛VerifyError,检查内容如下:

 

      1. 文件格式验证:验证class文件格式规范,例如: class文件是否已魔术0xCAFEBABE开头 , 主、次版本号是否在当前虚拟机处理范围之内等

 

      2. 元数据验证:这个类是否继承了不允许被继承的类(被final修饰的)、如果这个类的父类是抽象类,是否实现了起父类或接口中要求实现的所有方法。

 

      3. 字节码验证:进行数据流和控制流分析,这个阶段对类的方法体进行校验分析,这个阶段的任务是保证被校验类的方法在运行时不会做出危害虚拟机安全的行为。如:保证访法体中的类型转换有效,例如可以把一个子类对象赋值给父类数据类型,这是安全的,但不能把一个父类对象赋值给子类数据类型、保证跳转命令不会跳转到方法体以外的字节码命令上。

 

      4. 符号引用验证:字段和方法的访问性(private、protected、public、default)是否可被当前类访问。

 

 

 

准备

 

为静态变量或常量分配存储空间,将其初始化为默认值,这些空间都在方法区中分配。

 

 

 

解析

 

将虚拟机常量池中的符号引用替换成直接引用。

 

解析分为以下4类:

  1. 类或接口解析
  2. 字段解析
  3. 方法解析
  4. 接口方法解析

 

 

初始化

 

初始化阶段会做几件事

  1. 对静态块、构造函数、父类进行初始化。
  2. 对准备阶段初始化为默认值的静态变量或常量,进行赋值。

 

 

 

子类和父类加载顺序

     
 

 

 

如何实现自定义类加载器?

 

  1. 继承ClassLoader
  2. 重写ClassLoader的findClass()方法。

 

 

 

为什么研究类加载全过程?

 

    1. 有助于了解JVM运行过程
    2. 更深入了解java动态性(热部署,动态加载),提高程序的灵活性

猜你喜欢

转载自youyu4.iteye.com/blog/2353216