JVM学习之Java类的加载机制

文章目录
  1. JVM学习之Java类的加载机制
    1. I. 什么是类的加载
      1. 1. 加载哪里的class文件?
      2. 2. 数据结构
      3. 3. class对象
    2. II. 类加载过程
      1. 1. 加载
      2. 2. 验证
      3. 3. 准备
      4. 4. 解析
      5. 5. 初始化
        1. a. 初始化步骤
        2. b. 初始化的时机
      6. 6. 卸载
      7. III. 类加载器
      8. 1. 启动类加载器(BootStrap ClassLoader)
      9. 2. 扩展类加载器(Extension ClassLoader)
      10. 3. 应用类加载器(Application ClassLoader)
      11. 4. 自定义类加载器(User ClassLoader)
      12. 5.类加载机制
      13. 6.类的加载
      14. IV. 双亲委托
    3. V. 其他
      1. 参考:
      2. 个人博客: Z+|blog
      3. 声明
      4. 扫描关注

JVM学习之Java类的加载机制

平常我们使用java的多,深入到jvm层的机会却很少,平时若不关注,也不会清楚java文件编译后的class文件是如何被jvm加载到内存,如何进行初始化,如何进行运行的

因此这里主要学习的目标就是class文件的加载,会包含以下内容:

  • 什么是类加载
  • 类加载的过程
  • 什么时候触发类加载
  • 类加载器
  • 双亲委托机制

I. 什么是类的加载

简单来讲,类加载就是将class文件中的二进制,读取到内存中,解析其中定义的数据结构,然后在运行时方法区创建对应的数据结构,在堆内创建对应的class对象,而这个class对象,就是封装了对应的数据结构,和相关数据的访问操作方法;

上面的这一段简述中,却包含以下几个点:

1. 加载哪里的class文件?

第一步就是要明确的获取到对应的class文件了,jvm支持以下几个case中获取

  • 本地系统
  • 从网络上获取
  • 从数据库(or缓存等第三方存储)中获取
  • 从jar,zip包获取(比如我们依赖的第三方jar,大部分都是这种方式了)
  • 源码编译获取(如我们常用的Groovy脚本,源码方式存在,由GroovyEngine加载时就是源码编译成class文件之后由jvm加载的)

2. 数据结构

将class文件加载到内存后,一是在堆内创建class对象,一是在运行时方法区内创建对应的数据结构,具体的数据结构主要应该是类型信息

  • 类的方法代码,变量名,方法名,访问权限,返回值等

  • 类(静态)变量也存储在方法区

这一块有必要在jvm的内存分配中详细的研究下,每个存储区间到底干嘛用的,内部存写啥,先留一个坑位

3. class对象

class对象是在堆内创建,反射机制就是主要利用它来实现,通过class对象基本可以完全的操作这个类(包括创建对象,访问成员,调用方法)

II. 类加载过程

类加载过程主要包括: 加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载

用一张图来表示整个过程,且会带上每个过程主要干嘛用的

类加载过程

1. 加载

加载作为类加载的第一个过程,主要就是将class文件代表的二进制,加载到内存中

  • 获取class对应的二进制流(可以从任何能获取到的地方读取对应的二进制流)
  • 将二进制流的静态存储结构转换为方法区的运行时数据结构
  • 在堆内创建class对象

上面的三个过程中,最灵活的就是获取二进制的过程,可以按照你的实际场景,从各种地方捞出数据

2. 验证

主要是验证class文件是否合法,有没有被篡改等,属于连接的一个过程

  • 文件格式验证:魔数校验,jdk版本校验
  • 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外
  • 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  • 符号引用验证:确保解析动作能正确执行。

3. 准备

简单来说就是准备好静态变量的存储空间,并设置默认值,属于连接的一个过程

  • 正式为类分配内存
  • 为类变量设置默认的初始化值(不执行实际的赋值语句,这里专指基本类型的零值,对象的null)
  • 对static final 变量赋与代码中实际的值

4. 解析

简单来讲就是将常量池内的符号引用替换成实际引用,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行,同样属于连接的一个过程

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

5. 初始化

为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化

准备阶段为类变量赋上了默认值,这里则主要是初始化代码中的赋值,一般而言根据实际定义的顺序进行初始化

a. 初始化步骤

  • 若类没有被加载连接,则优先加载
  • 若父类没有被初始化,则优先初始化父类
  • 执行类的初始化语句(直接赋值,静态代码块)

b. 初始化的时机

  • new创建一个对象时
  • 访问或修改类的静态变量,执行静态方法
  • 反射调用
  • 子类被使用
  • jvm启动时指定

6. 卸载

简单来说就是用完了,收拾线程的过程

  • 程序执行完成
  • 异常
  • 系统层面错误
  • System.exit()

III. 类加载器

可以理解为类加载器就是用来加载类的工具,同一个类被不同的类加载器加载之后,也认为他们是不同的

四种类加载器:自定义类加载器,应用类加载器,扩展类加载器,启动类加载器

1. 启动类加载器(BootStrap ClassLoader)

源头,根,负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的

2. 扩展类加载器(Extension ClassLoader)

该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载DK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器

3. 应用类加载器(Application ClassLoader)

该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

4. 自定义类加载器(User ClassLoader)

自己实现的继承ClassLoader的加载器,可以按照自己的意愿,从某些地方加载类

5.类加载机制

  • 全盘负责
    • 当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
  • 父类委托
    • 先尝试让父类加载器来加载,当父类做不到时,再自己来做
  • 缓存机制
    • 缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效

6.类的加载

类加载有三种方式:

  • 1、命令行启动应用时候由JVM初始化加载

  • 2、通过Class.forName()方法动态加载

    • 加载class到内存,并执行static块
  • 3、通过ClassLoader.loadClass()方法动态加载
    • 只加载class文件到jvm,在class.newInstance()时,执行static块

IV. 双亲委托

双亲委托,就是来了一个类加载,先扔给上面去处理,层层上传,只有上面处理不了时,才自己来决定

有啥好处?

  • 系统类防止内存中出现多份同样的字节码
  • 保证Java程序安全稳定运行

说明:双亲委托机制是可以被破坏的

V. 其他

参考:

个人博客: Z+|blog

基于hexo + github pages搭建的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

声明

尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见识有限,如发现bug或者有更好的建议,随时欢迎批评指正

扫描关注

QrCode

# JDK, Java

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×