JVM——类加载机制

《深入理解Java虚拟机》学习笔记

类加载的时机

有且只有5种情况下:

  1. 使用new实例化对象,读取或者设置一个静态变量(final修饰的静态变量除外,因为它已经在编译期被放到了常量池中了)
  2. 反射触发
  3. 初始化一个类时,父类会执行类加载
  4. 虚拟机启动时,主类会执行类加载
  5. 方法句柄,MethodHandle

类的生命周期

image-20190501090804120

类加载的过程

加载

三个步骤:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据入口

验证

确保class文件中的字节流中包含的信息是否符合虚拟机的要求

准备

正式为类变量分配内存并设置类变量初始值

  • public static int value = 123
    • 变量value准备阶段过后值为0,因为这时候尚未开始执行任何java方法
  • public static final int valve
    • 变量valve准备阶段过后值为123,因为被final修饰了

解析

虚拟机将常量池内的符号引用替换为直接引用的过程

什么是符号引用?什么是直接引用

  • 符号引用:以一组符号来描述所引用的目标
  • 直接引用:直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄

初始化

执行类构造器

双亲委派模型

类加载器

从虚拟机角度,有两种加载器:

加载器 语言 代码
启动类加载器 c++ BootstrapClassLoader
其他类加载器 java java.lang.ClassLoader

从java开发人员角度

加载器 路径 代码
启动类加载器 \lib BootstrapClassLoader
扩展类加载器 \lib\ext sun.misc.Launcher$ExtClassLoadr
应用程序类加载器 用户类路径上所指定的类库 ClassLoader

类加载器之间的关系

image-20190501094604432

双亲委派模型

定义

除顶层类加载器外,其余类加载器都应当有自己对应的父类加载器。双亲父母一辈的意思,并不是指两个

工作过程

如果一个类加载收到加载请求,它会首先让父加载器加载,父加载器加载失败,才会自己去加载

优点

可以通过类本身和其类加载器一同确定其在Java虚拟机中的唯一性

破坏双亲委派系统

什么场景下需要破坏

  • 实现隔离性,如tomcat。tomcat服务器中可能部署多个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,要保证每个应用程序的类库是独立的,相互隔离。tomcat为了实现隔离性,每个webappClassLoader加载自己的目录下的class文件
  • SPI串行外接接口,如JDBC:父类加载器无法加载到所需的文件,Driver接口定义在jdk中,实现由服务商提供,不会放在/lib下,只能由启动类加载器委托子类来加载

如何破坏

有三种方式:

  1. 重写loadClass()方法,loadClass中包含了双亲委派的逻辑,通常自定义classLoader的时候会复写findClass
  2. Thread类中的setContextClassLoader,作用是父类加载器请求子类加载器去完成加载的动作
  3. OSGI,动态模块系统。

你可能感兴趣的:(JVM——类加载机制)