加载

在加载阶段, 虚拟机需要完成以下3件事情:
1) 通过一个类的全限定名来获取定义此类的二进制字节流。
2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3) 在内存中生成一个代表这个类的java.lang.Class对象, 作为方法区这个类的各种数据的访问入口。
虚拟机规范的这3点要求其实并不算具体, 因此虚拟机实现与具体应用的灵活度都是相当大的。 例如“通过一个类的全限定名来获取定义此类的二进制字节流”这条, 它没有指明二进制字节流要从一个Class文件中获取, 准确地说是根本没有指明要从哪里获取、 怎样获取。虚拟机设计团队在加载阶段搭建了一个相当开放的、 广阔的“舞台”, Java发展历程中, 充满创造力的开发人员则在这个“舞台”上玩出了各种花样, 许多举足轻重的Java技术都建立在这一基础之上, 例如:从ZIP包中读取, 这很常见, 最终成为日后JAR、 EAR、 WAR格式的基础。从网络中获取, 这种场景最典型的应用就是Applet。

验证

  Java语言本身是相对安全的语言( 依然是相对于C/C++来说),使用纯粹的Java代码无法做到诸如访问数组边界以外的数据、 将一个对象转型为它并未实现的类型、 跳转到不存在的代码行之类的事情, 如果这样做了, 编译器将拒绝编译。 但前面已经说过, Class文件并不一定要求用Java源码编译而来, 可以使用任何途径产生, 甚至包括用十六进制编辑器直接编写来产生Class文件。 在字节码语言层面上, 上述Java代码无法做到的事情都是可以实现的,至少语义上是可以表达出来的。 虚拟机如果不检查输入的字节流, 对其完全信任的话, 很可能会因为载入了有害的字节流而导致系统崩溃, 所以验证是虚拟机对自身保护的一项重要工作。

验证阶段大致上会完成下面4个阶段的检验动作:

文件格式验证:

  验证字节流是否符合Class文件格式的规范

元数据验证:

  对类的元数据信息进行语义校验

字节码验证:

  主要目的是通过数据流和控制流分析,确定程序语义是合法的、 符合逻辑的。

符号引用验证:

  符号引用验证可以看做是对类自身以外( 常量池中的各种符号引用) 的信息进行匹配性校验, 通常需要校验下列内容:符号引用中通过字符串描述的全限定名是否能找到对应的类。在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。符号引用中的类、 字段、 方法的访问性( private、 protected、 public、 default) 是否可被当前类访问。

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段, 这些变量所使用的内存都将在方法区中进行分配。

public static int value=123;   验证阶段value=零值
#因为这时候尚未开始执行任何Java方法, 而把value赋值为123的putstatic指令是程序被编译后, 存放于类构造器< clinit> ( ) 方法之中, 所以把value赋值为123的动作将在初始化阶段才会执行。

public static final int value=123; 验证阶段value=123
#如果类字段的字段属性表中存在ConstantValue属性, 那在准备阶段变量value就会被初始化为ConstantValue属性所指定的值。编译时Javac将会为value生成ConstantValue属性, 在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。

  • 符号引用( Symbolic References):

符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量, 只要使用时能无歧义地定位到目标即可。 符号引用与虚拟机实现的内存布局无关, 引用的目标并不一定已经加载到内存中。 各种虚拟机实现的内存布局可以各不相同, 但是它们能接受的符号引用必须都是一致的, 因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。(编译的时候,不知道存储地址,用符号)

  • 直接引用( Direct References):

直接引用可以是直接指向目标的指针、 相对偏移量或是一个能间接定位到目标的句柄。 直接引用是和虚拟机实现的内存布局相关的, 同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同。 如果有了直接引用, 那引用的目标必定已经在内存中存在。(加载后,知道在内存中的地址,吧之前在class中的符号替换为指针、或句柄)

  解析动作主要针对类或接口、 字段、 类方法、 接口方法、 方法类型、 方法句柄和调用点限定符7类符号引用进行 
关于理解“将常量池内的符号引用替换为直接引用”  参见:  https://blog.csdn.net/qq_34402394/article/details/72793119

初始化

前面的动作完全由虚拟机主导和控制。 到了初始化阶段, 才真正开始执行类中定义的Java程序代码( 或者说是字节码) 。

public class Test{
static{
i=0; //给变量赋值可以正常编译通过
System.out.print( i) ; //这句编译器会提示"非法向前引用"
}
static int i=1;
}

<clinit>()方法对于类或接口来说并不是必需的,如果一个类中没有静态语句块,也没有对变量的赋值操作,那么编译器可以不为这个类生成<clinit>()方法。

<clinit>() 方法类和接口区别:

  • 类

虚拟机会保证在子类的<clinit>() 方法执行之前,父类的<clinit>()方法已经执行完毕。也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作

  • 接口

接口与类不同的是,执行接口的<clinit>()方法不需要先执行父接口的<clinit>()方法。只有当父接口中定义的变量使用时,父接口才会初始化。

  虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个进程阻塞,在实际应用中这种阻塞往往是很隐蔽的。同一个类加载器下,一个类型只会初始化一次。

ps:可以想一下,为什么mysql使用jdbc的驱动是需要 Class.forName("com.mysql.jdbc.Driver");

为什么不直接new  com.mysql.jdbc.Driver(),对象而是要去DriverManager注册。

参考《深入理解java虚拟机》

java jvm虚拟机类加载过程的更多相关文章

  1. JVM虚拟机 类加载过程与类加载器

    目录 前言 类的生命周期 类加载过程 加载 连接 验证 准备 解析 初始化 类加载器 三大类加载器 双亲委派模型 概念 为什么要使用双亲委派模型 源码分析 反双亲委派模型 参考 前言 类装载器子系统是 ...

  2. java jvm虚拟机类加载器

    在Java中任意一个类都是由这个类本身和加载这个类的类加载器来确定这个类在JVM中的唯一性. 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到J ...

  3. JVM的类加载过程以及双亲委派模型详解

    JVM的类加载过程以及双亲委派模型详解 这篇文章主要介绍了JVM的类加载过程以及双亲委派模型详解,类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象 ...

  4. jvm学习002 虚拟机类加载过程以及主动引用和被动引用

    虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为 ...

  5. JVM虚拟机-类加载器子系统

    转自博客:http://www.cnblogs.com/muffe/p/3541189.html   还有一些自己补充的知识点 一.类加载器基本概念 顾名思义,类加载器(class loader)用来 ...

  6. 深入理解JVM - 虚拟机类加载机制 - 第七章

    类加载的时机类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括了:加载/验证/准备/解析/初始化/使用/卸载七个阶段.其中验证/准备和解析统称为连接(Linking). 加载.验证.准 ...

  7. JVM 虚拟机&&类加载(一)

    虚拟机 虚拟机简介 Java 虚拟机(JVM)是运行java程序的抽象计算机,它是计算机设备的规范,可以采用不同方式进行实现,java 程序通过运行在JVM中实现跨平台,一次编译到处运行,不同的操作系 ...

  8. 类文件的结构、JVM 的类加载过程、类加载机制、类加载器、双亲委派模型

    一.类文件的结构 我们都知道,各种不同平台的虚拟机,都支持 "字节码 Byte Code" 这种程序存储格式,这构成了 Java 平台无关性的基石.甚至现在平台无关性也开始演变出 ...

  9. Java JVM——2.类加载器子系统

    概述 类加载器子系统在Java JVM中的位置 类加载器子系统的具体实现 类加载器子系统的作用 ① 负责从文件系统或者网络中加载.class文件,Class 文件在文件开头有特定的文件标识. ② Cl ...

随机推荐

  1. 算法问题实战策略 BOARDCOVER

    地址 https://algospot.com/judge/problem/read/BOARDCOVER 解法 DFS 最近似乎在简单DFS上花费太多时间了 首先扫描地图 统计可覆盖的元素个数 如果 ...

  2. JMeter基础知识系列三

    JMeter测试结果字段的意义: Label:定义HTTP请求名称. Samples:表示这次测试中一共发出了多少个请求. Average:平均响应时长,当使用了Transaction Control ...

  3. (day67)作业

    有以下广告数据(实际数据命名可以略做调整) ad_data = { tv: [ {img: 'img/tv/001.png', title: 'tv1'}, {img: 'img/tv/002.png ...

  4. github 码云 chrome文件树形插件

    偶然间看到github有一个树形插件,对于代码层级较多的项目来说体验提升了很多 github的chrome插件 chrome商店: https://chrome.google.com/webstore ...

  5. css 适配

    https://blog.csdn.net/weixin_35467885/article/details/80778992 1.通过link方法 link方法引入媒体类型其实就是在标签引用样式的时候 ...

  6. nui-app 笔记

    https://uniapp.dcloud.io

  7. 机器学习--matplotlib绘制各种图表

    机器学习三剑客:numpy.pandas.matplotlib NumPy系统是Python的一种开源的数值计算扩展.这种工具可用来存储和处理大型矩阵. pandas 是基于numpy的一种工具,该工 ...

  8. php程序内存优化之数组操作优化

    一.前言这篇文章其实是上篇文章的内存优化部分.博主的php程序在执行的时候,报错: Out of memory (allocated 364904448) (tried to allocate 262 ...

  9. IT兄弟连 HTML5教程 HTML5的学习线路图 第二、三阶段

    第二阶段编写用户交互功能 通过第一阶段的学习虽说可以完成页面制作,但并不完美,不能算是合格的前端工程师,所以要继续学习如图1.13中的第二阶段内容.现在的Web页面都融入了大量的特效,并且多数需要与用 ...

  10. 【linux运维】linux系统上忘记密码如何操作

    目录 红帽系统忘记密码操作 红帽系统设置ip,主机名 centos系统忘记密码操作 一.红帽系统忘记密码操作 1)再出现以下界面后按键盘e键 2)进入以下界面后,再次按e键 3)使用上下键选择第2项或 ...