JVM类加载、验证、准备、解析、初始化、卸载过程详解(中)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: JVM类加载、验证、准备、解析、初始化、卸载过程详解(中)

1 加载的定位

“加载”是“类加载”(Class Loading)过程的第一步。

1.1 加载过程

JVM主要做如下事情:


通过类的全限定名(保证全局唯一)获取该类的二进制字节流(class文件)

在程序运行过程中,当要访问一个类时,若发现这个类尚未被加载,并满足类初始化的条件时,就根据要被初始化的这个类的全限定名找到该类的二进制字节流,开始加载过程。

把类加载阶段的“通过类的全限定名来获取该类的二进制字节流”这个动作交给虚拟机之外的类加载器来完成的好处在于,可自行实现类加载器来加载其他格式的类,只要是二进制字节流就行,这就大大增强加载器的灵活性。

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

在内存中创建一个该类的java.lang.Class对象,作为方法区该类的各种数据的访问入口,所以所有类都可以调用 getClass 方法

程序在运行中所有对该类的访问都通过这个类对象,也就是这个Class对象是提供给外界访问该类的接口

1.2 加载源

JVM规范对于加载过程给予了较大的宽松度。一般二进制字节流都从已经编译好的本地class文件中读取,此外还可以从以下地方读取


zip包

Jar、War、Ear等

其它文件生成

由JSP文件中生成对应的Class类

数据库中

将二进制字节流存储至数据库中,然后在加载时从数据库中读取.有些中间件会这么做,用来实现代码在集群间分发

网络

从网络中获取二进制字节流,比如Applet

运行时动态计算生成

动态代理技术,用PRoxyGenerator.generateProxyClass为特定接口生成形式为"*$Proxy"的代理类的二进制字节流

1.3 类和数组加载过程的区别

数组也有类型,称为“数组类型”,如:

String[] str = new String[10];

这个数组的数组类型是Ljava.lang.String,而String只是这个数组的元素类型。

当程序在运行过程中遇到new关键字创建一个数组时,由JVM直接创建数组类,再由类加载器创建数组中的元素类型。


而普通类的加载由类加载器创建。既可以使用系统提供的引导类加载器,也可以由用户自定义的类加载器完成(即重写一个类加载器的loadClass()方法)

1.4 加载过程的注意点

  • JVM规范并未给出类在方法区中存放的数据结构
    类完成加载后,二进制字节流就以特定的数据结构存储在方法区中,但存储的数据结构是由虚拟机自己定义的,虚拟机规范并没有指定

JVM规范并没有指定Class对象存放的位置

在二进制字节流以特定格式存储在方法区后,JVM会创建一个java.lang.Class类的对象,作为本类的外部访问接口

既然是对象就应该存放在Java堆中,不过JVM规范并没有给出限制,不同的虚拟机根据自己的需求存放这个对象

HotSpot将Class对象存放在方法区.

加载阶段和链接阶段是交叉的

类加载的过程中每个步骤的开始顺序都有严格限制,但每个步骤的结束顺序没有限制.也就是说,类加载过程中,必须按照如下顺序开始:

加载 -> 链接 -> 初始化


但结束顺序无所谓,因此由于每个步骤处理时间的长短不一就会导致有些步骤会出现交叉

2 验证

验证阶段比较耗时,它非常重要但不一定必要(因为对程序运行期没有影响),如果所运行的代码已经被反复使用和验证过,那么可以使用-Xverify:none参数关闭,以缩短类加载时间

2 验证

验证阶段比较耗时,它非常重要但不一定必要(因为对程序运行期没有影响),如果所运行的代码已经被反复使用和验证过,那么可以使用-Xverify:none参数关闭,以缩短类加载时间

2.2 验证的必要性

虽然Java语言是一门安全的语言,它能确保程序猿无法访问数组边界以外的内存、避免让一个对象转换成任意类型、避免跳转到不存在的代码行.也就是说,Java语言的安全性是通过编译器来保证的.


但是我们知道,编译器和虚拟机是两个独立的东西,虚拟机只认二进制字节流,它不会管所获得的二进制字节流是哪来的,当然,如果是编译器给它的,那么就相对安全,但如果是从其它途径获得的,那么无法确保该二进制字节流是安全的。


通过上文可知,虚拟机规范中没有限制二进制字节流的来源,在字节码层面上,上述Java代码无法做到的都是可以实现的,至少语义上是可以表达出来的,为了防止字节流中有安全问题,需要验证!

2.3 验证的过程

  • 文件格式验证
    验证字节流是否符合Class文件格式的规范,并且能被当前的虚拟机处理.
  • 本验证阶段是基于二进制字节流进行的,只有通过本阶段验证,才被允许存到方法区

后面的三个验证阶段都是基于方法区的存储结构进行,不会再直接操作字节流.

通过上文可知,加载开始前,二进制字节流还没进方法区,而加载完成后,二进制字节流已经存入方法区

而在文件格式验证前,二进制字节流尚未进入方法区,文件格式验证通过之后才进入方法区

也就是说,加载开始后,立即启动了文件格式验证,本阶段验证通过后,二进制字节流被转换成特定数据结构存储至方法区中,继而开始下阶段的验证和创建Class对象等操作

这个过程印证了:加载和验证是交叉进行的


元数据验证

对字节码描述的信息进行语义分析,确保符合Java语法规范。

字节码验证

验证过程的最复杂的阶段。 本阶段对数据流和控制流(主要为方法体)进行语义分析。字节码验证将对类的方法进行校验分析,保证被校验的方法在运行时不会做出危害虚拟机的事,一个类方法体的字节码没有通过字节码验证,那一定有问题,但若一个方法通过了验证,也不能说明它一定安全。

符号引用验证

发生在JVM将符号引用转化为直接引用的时候,这个转化动作发生在解析阶段,对类自身以外的信息进行匹配校验,确保解析能正常执行.


目录
相关文章
|
4月前
|
域名解析 网络协议 安全
反向DNS解析是从IP地址到域名的映射,主要作用于验证和识别,提高通信来源的可信度和可追溯性
在网络世界中,反向DNS解析是从IP地址到域名的映射,主要作用于验证和识别,提高通信来源的可信度和可追溯性。它在邮件服务器验证、网络安全等领域至关重要,帮助识别恶意行为,增强网络安全性。尽管存在配置错误等挑战,但正确管理下,反向DNS解析能显著提升网络环境的安全性和可靠性。
271 3
|
5月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
201 3
|
5月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
78 3
|
5月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
79 3
|
5月前
|
Python
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
44 1
|
6月前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
161 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
7月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
62 3
|
7月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
365 0
|
8月前
|
存储 前端开发 Java
(二)JVM成神路之剖析Java类加载子系统、双亲委派机制及线程上下文类加载器
上篇《初识Java虚拟机》文章中曾提及到:我们所编写的Java代码经过编译之后,会生成对应的class字节码文件,而在程序启动时会通过类加载子系统将这些字节码文件先装载进内存,然后再交由执行引擎执行。本文中则会对Java虚拟机的类加载机制以及执行引擎进行全面分析。
149 0
|
8月前
|
Java Perl
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
114 0

热门文章

最新文章

推荐镜像

更多