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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 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
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
48 3
|
2月前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
117 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
3月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
27 3
|
3月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
194 0
|
4月前
|
存储 缓存 自然语言处理
(三)JVM成神路之全面详解执行引擎子系统、JIT即时编译原理与分派实现
执行引擎子系统是JVM的重要组成部分之一,在JVM系列的开篇曾提到:JVM是一个架构在平台上的平台,虚拟机是一个相似于“物理机”的概念,与物理机一样,都具备代码执行的能力。
|
4月前
|
存储 前端开发 Java
(二)JVM成神路之剖析Java类加载子系统、双亲委派机制及线程上下文类加载器
上篇《初识Java虚拟机》文章中曾提及到:我们所编写的Java代码经过编译之后,会生成对应的class字节码文件,而在程序启动时会通过类加载子系统将这些字节码文件先装载进内存,然后再交由执行引擎执行。本文中则会对Java虚拟机的类加载机制以及执行引擎进行全面分析。
|
4月前
|
Java Perl
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
|
4月前
|
存储 安全 Java
开发与运维引用问题之JVM类加载过程如何解决
开发与运维引用问题之JVM类加载过程如何解决
31 0
|
4月前
|
存储 算法 Java
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
|
1月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
37 4