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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 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并不会重复执行初始化操作。


目录
相关文章
|
20天前
|
存储 缓存 自然语言处理
(三)JVM成神路之全面详解执行引擎子系统、JIT即时编译原理与分派实现
执行引擎子系统是JVM的重要组成部分之一,在JVM系列的开篇曾提到:JVM是一个架构在平台上的平台,虚拟机是一个相似于“物理机”的概念,与物理机一样,都具备代码执行的能力。
|
20天前
|
存储 前端开发 Java
(二)JVM成神路之剖析Java类加载子系统、双亲委派机制及线程上下文类加载器
上篇《初识Java虚拟机》文章中曾提及到:我们所编写的Java代码经过编译之后,会生成对应的class字节码文件,而在程序启动时会通过类加载子系统将这些字节码文件先装载进内存,然后再交由执行引擎执行。本文中则会对Java虚拟机的类加载机制以及执行引擎进行全面分析。
|
26天前
|
Java Perl
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
|
27天前
|
存储 安全 Java
开发与运维引用问题之JVM类加载过程如何解决
开发与运维引用问题之JVM类加载过程如何解决
18 0
|
29天前
|
存储 算法 Java
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
|
2月前
|
安全 前端开发 Java
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
21 0
|
2月前
|
存储 监控 算法
|
2月前
|
存储 安全 前端开发
JVM(二)-类加载子系统
JVM(二)-类加载子系统
14 0
|
3月前
|
前端开发 Java 应用服务中间件
【JVM系列笔记】类加载
类加载器分为两类,一类是Java代码中实现的,一类是Java虚拟机底层源码实现的。常见的类加载器有启动类加载器,拓展类加载器,应用类加载器以及自定义类加载器。以及类加载机制,双亲委托策略,以及打破双亲委托策略的几种方式。
65 0
|
7天前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法