2019独角兽企业重金招聘Python工程师标准>>>

3.类加载的全过程

java虚拟机中类加载的全过程,也就是加载、验证、准备、解析和初始化这五个阶段所执行的具体动作。

1.加载

加载阶段,虚拟机需要完成以下3件事情:

①通过一个类的全限定名来获取此类的二进制流。——开发人员可控性最强的阶段(常见从jar包中读取)

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

③在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个累的各种数据的访问入口。——这是一个特殊的对象,它存放在方法区中

这里对加载的第一阶段还需要进行更加详细的描述:

相对于类加载过程的其他阶段,一个非数组类的加载阶段(准确地说,是加载阶段中获取类的二进制字节流的阶段)是开发人员可控性最强的,因为加载阶段既可以使用系统提供的引导类加载器来完成,也可以由用户自定义的类加载器去完成。开完人员可以通过定义自己的类加载器去控制字节流的获取方式(即重写一个类加载器的loadClass()方法)。

对于数组类而言,情况就有所不同,数组类本身不通过类加载器创建,它是由java虚拟机直接创建的。但是数组类与类加载器仍然有密切的关系,因为数组类的元素类型(Element Type,指的是数组去掉所有维度的类型)最终是要靠类加载器去创建,一个数组类创建的过程就遵循以下规则:

①如果数组的组件类型是引用类型,那就递归采用本节中定义的加载过程去加载这个组件类型,数组C将在加载该组件类型的类加载器的类名称空间上被标志(这点很重要,之后会介绍到,一个类必须与类加载器一起确定唯一性)。

②如果数组的组件类型不是引用类型(例如int[]数组),java虚拟机将会把数组c标记为与引导类加载器关联。

③数组类的可见性与它的组件类型的可见性一致,如果组件类型不是引用类型,那数组的可见性将默认为public。

加载阶段还未结束,连接阶段可能已经开始了,虽然两个阶段可能交叉进行,但是两个阶段的开始时间仍然保持着固定的先后顺序

2.验证

这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,且不会危害虚拟机自身的安全。

为什么有验证阶段?

Java语言本身是相对安全的语言(依然是相对于C/C++来说),使用纯粹的Java代码无法做到诸如访问数组边界以外的数据、将一个对象转型为它并为实现的类型、跳转到不存在的代码行之类的事情,如果这样做了,编译器将拒绝编译。

但是前面也说过Class文件并不一定从Java源码编译而来,甚至可以直接编写Class文件。在字节码层面上,上述Java语言无法做到的事都是可以实现的,因此必须有验证阶段,防止输入有害字节流而导致系统崩溃,所以验证是虚拟机对自身保护的一项重要工作。

如果验证到输入的字节流不符合Class文件格式的越是,虚拟机就应抛出一个java.lang.VerifyError异常或其子类异常。

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

文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。

主要目的是保证输入的字节流能正确的解析并存储与方法区内,格式上符合描述一个Java类型信息的要求。只有通过了这个阶段的验证后,字节流才会进入内存的方法区内进行存储,所以后面的3个阶段都是基于方法区的存储结构进行的,不会再直接操作字节流,

元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求。

字节码验证:主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在第二阶段对元数据中的数据类型做完校验之后,这个阶段将对累的方法体进行校验分析,保证北郊眼泪的方法在运行时不会做出危害虚拟机安全的事件。

符号引用验证:最后一个阶段的校验发生在虚拟机将符号引用转换为直接引用的时候,这个转换动作将在连接的第三阶段——解析阶段中发生。符号引用验证可以看做是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验。

目的是确保解析动作能够正确执行,如果无法通过符号引用验证,那么将会抛出一个java.lang.IncompatibloeClassChangeError异常的子类。

3.准备

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

两点需要强调:①这时候进行内存分配的仅包括类变量,而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在java堆中。②这里所说的初始值“通常情况”下是数据类型的零值。相对也有一些是特殊情况,如果类字段的字段属性表存在ConstantValue属性,那么准备阶段变量value就会被初始化为ConstantValue属性所指定的值,如代码

public static final int value=123;

因为有了final,所以编译时javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue将value赋值为123。

4.解析

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

符号引用(Symbolic Reference):符号引用可以使任何形式的字面量,只要使用时能无歧义的定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。各种虚拟机实现内存布局可以各不相同,但是他们能接受的符号引用必须都是一致的,因为符号引用的字面量形式明确定义在java虚拟机规范的class文件格式中。

直接引用(Direct Reference):直接引用可以使直接指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般会不同。如果有了直接引用,那引用的目标必定已经在内存中存在。

解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

5.初始化

类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全是由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码(或者说字节码)。

初始化阶段是执行类构造器<clinit>()方法的过程。

<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并而成的。

需要注意的是,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。

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

<clinit>()方法与类的构造函数(或者说实例构造器<init>()方法)不同,它不需要显示的调用父类构造器,虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。因此第一个被执行的<clinit>()方法的类肯定是java.lang.Object

③由于父类的<clinit>()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作。

④<clinit>()方法对于类或接口来说不是必须的,如果一个类中没有静态与太快,也没有对变量的赋值操作,编译器可以不为这个类生成<clinit>()方法。

⑤接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,需要注意的是,执行接口的<clinit>()方法不需要先执行父接口的<clinit>()方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时,也一样不会执行接口的<clinit>()方法。

⑥虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法。

转载于:https://my.oschina.net/u/3786691/blog/1807257

JVM——类加载机制(二)相关推荐

  1. JVM类加载机制讲解

    文章目录 前言 JVM类加载机制讲解 一.什么是JVM类加载机制? 二.类加载的时机 三.类加载的五个阶段 1.加载: 2.验证: 3.准备: 4.解析: 5.初始化: 四.什么类型的数据不会初始化? ...

  2. jvm类加载机制_JVM 类加载机制

    学习导图 一.为什么要学习类加载机制? 今天想跟大家唠嗑唠嗑 Java 的类加载机制,这是 Java 的一个很重要的创新点,曾经也是 Java 流行的重要原因之一. Oracle 当初引入这个机制是为 ...

  3. JVM(2)——JVM类加载机制

    一.JVM类加载机制简介 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 在Java语言里面 ...

  4. JVM类加载机制详解-20160812

    JVM类加载机制 一,类加载器体系     类加载器是沙箱的第一道防线,毕竟代码都是类加载器装入到JVM的.类加载体系通过使用不同的类加载器把类放 入不同的命名空间中,从而保护善意代码不受恶意代码的干 ...

  5. 面试题:请介绍 JVM 类加载机制

    JVM 类加载机制 Java 代码执行流程 类的生命周期 加载 验证 准备 解析 初始化 clinit 和 init 方法 类加载的时机 被动引用 类加载器 双亲委派机制 我们在前面分析JVM架构解析 ...

  6. JDK源码JVM类加载机制

    JVM类加载机制 首先我们的java小程序demo,经过编译后变成.class文件,他是如何加载到内存的将.class文件 内存中有两大对象:1.类的字节码对象,只有一份在内存.2.类对象会有多份 文 ...

  7. 【面试】JVM类加载机制

    本系列为大厂面试题系列的相关笔记,如有误,欢迎大家指正. JVM类加载机制 类加载器 虚拟机设计团队把加载动作放到JVM外部实现,以便于引用程序决定如何获取所需的类,JVM提供了三种类加载器 启动类加 ...

  8. 关于JVM类加载机制

    关于JVM类加载机制 一.Java指令运行程序流程 二.loadClass类加载过程 三.类加载器和双亲委派机制 类加载器初始化过程 双亲委派机制 LoadClass逻辑: 设计双亲委派机制用意: 全 ...

  9. JVM基础系列第7讲:JVM 类加载机制

    当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析.运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制.JVM 虚拟机执行 class 字节 ...

  10. jvm类加载机制_面试:对于JVM类加载机制深度解析

    目录: 前文回顾 JVM在什么情况下会加载一个类? 从实用角度出发,来看看验证.准备和初始化的过程 核心阶段:初始化 类加载器和双亲委派机制 1.前文回顾 咱们今天先来回顾一下昨天讲到的JVM整体的一 ...

最新文章

  1. 【计算机网络】网络层 : 总结 ( 功能 | 数据交换 | IP 数据报 | IPv4 地址 | IPv6 地址 | 路由选择协议 | 路由算法 )★★★
  2. python进阶(十七)xml(下)
  3. 委外订单_听听晚报-英特尔扩大芯片委外订单、苹果秋季或举行两场发布会
  4. 大新闻!Magic Leap造假,HoloLens即将入华商用
  5. 豆瓣9分,颠覆世界观的好书,每读一章就感叹一次:原来如此!(免费领)
  6. ios6.0,程序为横屏,出现闪退
  7. POJ-1904-King's Quest(强连通图)
  8. paip.java 多线程参数以及返回值Future FutureTask 的使用.
  9. svm出现浮点数与字符串不能计算的错误(label必须为 整形或浮点型)
  10. node.js室内装修风格选择系统毕业设计-附源码211552
  11. 《计算机系统基础》复习——简答题 01
  12. Xman的东西当然值钱了。每1单位高度的植物,就可以卖2美元,把减掉的植物都卖掉,就可以弥补罚单的损失了。你帮Xman计算一下一共可以卖多少钱。
  13. PageOffice 安装使用说明
  14. 2022年茶叶行业现状分析
  15. 《TCP/IP详解》卷一:The-internet-protocol-IP
  16. 中原银行实时风控体系建设实践
  17. 基于Python查询某个ip是否属于某个或多个ip段
  18. 大学生职业生涯规划——我的未来我做主
  19. Linux-CentOS7系统服务中systemctl命令介绍
  20. 51nod 1301 集合异或和 动态规划

热门文章

  1. P1165 日志分析 洛谷
  2. jQuery 生成随机字符
  3. css 对齐方式 分类
  4. [转]Banner设计“点横竖撇捺”
  5. 亲,C/C++/C#居然薄弱叻?不会吧,现在是HTML5+CSS3+javascript的时代?
  6. 在ASP.NET中执行URL重写(一)
  7. hdu 1423(LCS+LIS)
  8. 解决ASP.NET页面回车回发的问题
  9. JavaWEB开发国际化
  10. DataList 编辑记录时,更新取不到值的原因。