JVM 从入门到精通(三)类加载子系统1

简介: JVM 从入门到精通(三)类加载子系统1

文章目录


一、内存结构概述


二、类加载器和类的加载过程

2.1 类加载子系统作用

2.2 类加载器ClassLoader角色

2.3 类的加载过程

2.3.1 加载

2.3.2 链接(即验证、准备、解析)

2.3.3 初始化


三、类加载器分类

3.1 自定义类与核心类库的加载器

3.2 虚拟机自带的加载器

3.3 用户自定义加载器


四、ClassLoader的常用方法及获取方法

4.1 ClassLoader继承关系

4.2 代码示例


五、双亲委派机制

5.1 双亲委派机制工作原理

5.2 代码示例

5.3 双亲委派机制的优势

5.4 双亲委派机制在SPI中的应用

5.5 沙箱安全机制


六、其他

6.1 JVM中表示两个class对象是否为同一个类

6.2 对类加载器的引用

6.3 类的主动使用和被动使用


一、内存结构概述


如果自己想手写一个Java虚拟机的话,主要考虑哪些结构呢?


  • 类加载器
  • 执行引擎

20200606152316994.png


复杂版的详细图


9999999999.png


本文针对Class Loader SubSystem这一块展开讲解类加载子系统的工作流程。


二、类加载器和类的加载过程


2.1 类加载子系统作用


1.png


类加载子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识即16进制CA FE BA BE;


加载后的Class类信息存放于一块成为 方法区 的内存空间。除了类信息之外,方法区还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)


ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定


如果调用构造器实例化对象,则其实例存放在堆区


2.2 类加载器ClassLoader角色2.png


  1. class file 存在于本地硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候要加载到JVM当中来根据这个文件实例化出n个一模一样的实例。
  2. class file 加载到JVM中,被称为DNA元数据模板,放在方法区。
  3. 在.class文件 —> JVM —> 最终成为元数据模板,此过程就要一个运输工具(类装载器 Class Loader),扮演一个快递员的角色。


3.png


2.3 类的加载过程


看代码

public class HelloLoader {
    public static void main(String[] args) {
        System.out.println("谢谢ClassLoader加载我....");
        System.out.println("你的大恩大德,我下辈子再报!");
    }
}

它的加载过程是怎么样的呢?


执行 main() 方法(静态方法)就需要先加载承载类 HelloLoader

加载成功,则进行链接、初始化等操作,完成后调用 HelloLoader 类中的静态方法 main

加载失败则抛出异常


4.png


完整的流程图如下所示:加载 --> 链接(验证 --> 准备 --> 解析) --> 初始化


5.png


2.3.1 加载


通过一个类的全限定名获取定义此类的二进制字节流;


将这个字节流所代表的的静态存储结构转化为方法区的运行时数据;


在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口


加载class文件的方式


从本地系统中直接加载

通过网络获取,典型场景:Web Applet

从zip压缩包中读取,成为日后jar、war格式的基础

运行时计算生成,使用最多的是:动态代理技术

由其他文件生成,典型场景:JSP应用从专有数据库中提取.class文件,比较少见

从加密文件中获取,典型的防Class文件被反编译的保护措施


2.3.2 链接(即验证、准备、解析)


验证


目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。


主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。


准备


为类变量分配内存并且设置该类变量的默认初始值,即零值;


这里不包含用final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式初始化;


之类不会为实例变量分配初始化,类变量会分配在方法去中,而实例变量是会随着对象一起分配到java堆中。


解析


将常量池内的符号引用转换为直接引用的过程。


事实上,解析操作网晚会伴随着jvm在执行完初始化之后再执行


符号引用就是一组符号来描述所引用的目标。符号应用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄


解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT_Class_info/CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。


2.3.3 初始化


  1. clinit()即“class or interface initialization method”,注意他并不是指构造器init(),初始化阶段就是执行类构造器方法()的过程


  1. 此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。


  1. 我们注意到如果没有静态变量c,那么字节码文件中就不会有clinit方法


6.png7.png


构造器方法clinit()中指令按语句在源文件中出现的顺序执行


8.png


虚拟机必须保证一个类的clinit()方法在多线程下被同步加锁。


即一个类只需被clinit一次,之后该类的内部信息就被存储在方法区。


9.png


可以看到线程2并不会重复执行初始化操作。


目录
相关文章
|
1月前
|
前端开发 安全 Java
聊聊Java虚拟机(一)—— 类加载子系统
虚拟机就是一款用来执行虚拟计算机指令的计算机软件。它相当于一台虚拟计算机。大体上,虚拟机分为系统虚拟机和程序虚拟机。系统虚拟机就相当于一台物理电脑,里面可以安装操作系统;程序虚拟机是为了执行单个计算机程序而设计出来的虚拟机。其中 Java 虚拟机就是**执行 Java 字节码指令的虚拟机**。
37 2
|
5月前
|
前端开发 安全 Java
JVM类加载和双亲委派机制
JVM类加载和双亲委派机制
102 0
|
28天前
|
安全 Java 程序员
深入理解jvm - 类加载过程
深入理解jvm - 类加载过程
35 0
|
2月前
|
存储 前端开发 安全
浅谈 JVM 类加载过程
浅谈 JVM 类加载过程
32 0
|
2月前
|
存储 安全 Java
JVM类加载(类加载过程、双亲委派模型)
JVM类加载(类加载过程、双亲委派模型)
|
3月前
|
存储 算法 安全
面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)
面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)
47 0
|
5月前
|
安全 前端开发 Java
JVM概述和类加载子系统
我记得当年学java的时候,就很好奇,为什么我在IDEA上写一些代码(其实就是一堆我们人能知道的英文单词的组合加一些运算符),为什么就可以在windows上运行后执行我们的指令,而且还可以打成jar包去linux系统跑起来,为什么一份代码可以在不同平台运行呢?类是如何加载的?对象如何创建的以及都有哪些信息?我创建的对象被分配到哪个内存去了?java是怎么和我们操作系统打交道的又是怎么调用CPU为我们计算的?创建了对象分配了内存,为什么可以不用手动回收就可以自动清理内存等等等,相信你也同样有过这些困惑。
33 0
|
6月前
|
存储 安全 前端开发
【jvm系列-02】jvm的类加载子系统以及jclasslib的基本使用
【jvm系列-02】jvm的类加载子系统以及jclasslib的基本使用
49 0
|
1月前
|
存储 算法 Java
理解JVM的内存模型和垃圾回收算法
理解JVM的内存模型和垃圾回收算法
27 2
|
1月前
|
缓存 监控 算法
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
47 0