欢迎光临散文网 会员登陆 & 注册

Java类加载机制,你了解吗?

2020-12-26 13:38 作者:编程大战  | 我要投稿

1、类的加载

类的加载是指将类的.class文件读取进内存中,并将其放在JVM运行时数据区的方法区内,然后在堆中创建一个java.lang.Class对象,用于封装类在方法区中的数据结构,同时作为方法区数据的访问入口。

2、类的生命周期

类的生命周期指一个class文件从加载到卸载的整个过程

3、类的加载过程

JVM将类的加载分为三个阶段:装载(Load)链接(Link)初始化(Initialize)

3.1 装载:查找并加载类的二进制数据

在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的Java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

3.2 链接:验证、准备、解析

  • 验证
    校验字节码文件的正确性、安全性,包括四种验证:文件格式验证、元数据的验证、字节码验证、符号引用验证

  • 准备
    为类变量(static修饰的字段变量)分配内存并且设置该类变量的初始值,这里不包含final修饰的static,因为final在编译的时候就已经分配了。也不会为实例变量分配初始化,实例变量会随着对象分配到堆内存中。

  • 解析
    把常量池中的符号引用转换为直接引用,静态链接过程

3.3 初始化:初始化静态变量,执行静态代码块

3.3.1 类的初始化时机

如果一个类被直接引用,就会触发类的初始化。在Java中,直接引用的情况有:

  • 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法

  • 通过反射执行以上三种行为

  • 初始化子类的时候,会触发父类的初始化

  • 作为程序的入口直接运行时(main方法)

3.3.2 类初始化步骤

  • 假如这个类还没有被加载和链接,则程序先加载并连接该类(动态加载:主类在运行过程中如果使用到其他类,会逐步加载这些类 eg:jar包和war包中的类并不是一次性都加载到内存中,而是使用时才加载)

  • 假如该类的直接父类还没有被初始化,则先初始化其直接父类

  • 假如类中有初始化语句,则系统依次执行这些初始化语句

4、类加载后方法区存储内容

类被加载到方法区中后主要包含运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。

类加载器的引用:这个类到类加载器实例的引用

对应class实例的引用:类加载器在加载类信息放到方法区中后,会创建一个对应的Class 类型的对象实例放到堆(Heap)中, 作为开发人员访问方法区中类定义的入口和切入点。

5、类加载器

类加载过程主要通过类加载器实现,Java中有以下几种类加载器:

  • 引导类加载器(Bootstrap ClassLoader)
    负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar\charsets.jar等,由C++实现,不是ClassLoader子类,Java程序无法直接引用。

  • 拓展类加载器(Extension ClassLoader)
    负责加载支撑JVM运行的位于JRE的lib目录下的ext拓展目录中的类库

  • 应用类加载器(App ClassLoader)
    负责加载ClassPath路径下的类包,主要加载开发人员写的类

  • 自定义类加载器(Custom ClassLoader)
    负责加载用户自定义路径下的类包

类加载器之间存在父子层级结构:

6、双亲委派机制

6.1 定义

双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的加载路径下找不到指定类时,子类才会尝试自己去加载。

6.2 工作过程

  1. 当应用程序类加载器收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。

  2. 当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。

  3. 如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。

  4. 如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。

  5. 如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。

  6. 如果均加载失败,就会抛出ClassNotFoundException异常。

6.3 双亲委托机制实现源码(JDK 1.8)

6.4 双亲委托作用

  1. 沙箱安全机制:防止核心类库被篡改,自己写的java.lang.String不会被加载。

  2. 避免类的重复加载:当父加载器已经加载过该类时,子加载器就没必要重新加载一次,保证被加载类的唯一性。

7、自定义类加载器

8、如何打破双亲委派机制

核心:继承ClassLoader,重写类加载方法,实现加载逻辑,不委托给双亲加载





Java类加载机制,你了解吗?的评论 (共 条)

分享到微博请遵守国家法律