资讯专栏INFORMATION COLUMN

JVM类加载思维导图

Crazy_Coder / 3608人阅读

摘要:用一张思维导图尽可能囊括一下的类加载过程的全流程。本文参考自来自周志明深入理解虚拟机第版,拓展内容建议读者可以阅读下这本书。

用一张思维导图尽可能囊括一下JVM的类加载过程的全流程。

本文参考自来自周志明《深入理解Java虚拟机(第2版)》,拓展内容建议读者可以阅读下这本书。

文字版如下:

加载 Loading 过程

通过类的全限定名来获取定义此类的二进制字节流

非数组类的加载,由类加载器加载,可以是启动类加载器,也可以是用户自定义的类加载器

数组类的加载,不由类加载器创建,而是由JVM直接在内部创建

组件类型(数组降一维后的类型)是引用类型,递归调用加载过程直到降到一维类型后通过类加载器加载,数组类型最终标识为此类加载器所加载,数组类可见性和组件类型保持一致

组件类型不是引用类型而是原始类型,则该数组类型的类加载器将标识为启动类加载器,数组类型可见性为public

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

在内存中(HotSpot为方法区)生成一个代表了这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

类加载器

启动类加载器 Bootstrap ClassLoader,加载/lib中的类

拓展类加载器 Extension ClassLoader,加载/lib/ext中的类

应用程序类加载器 Application ClassLoader,加载用户类路径上的ClassPath中的类

自定义类加载器 User ClassLoader

连接 Linking 验证 Verification

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

是否以magic开头

主次版本号是否在虚拟机处理范围内

常量池中的常量是否有不支持的类型

指向的常量索引值是否有指向不存在常量或不符合类型常量的情况

CONSTANT_Utf8_info的常量是否符合utf8编码规范

Class文件各个部分及文件本身是否有被删除或附加的其他信息

元数据验证:字节码描述的信息进行语义分析

是否有父类

父类是否继承了不允许被继承的类(final的)

如果不是抽象类是否实现了其父类或接口之中要求实现的类

类中字段、方法是否与父类产生矛盾

覆盖了父类的final字段

不符合规范的方法重载
方法参数类型一致返回值类型不一致

字节码验证:通过数据流和控制流分析程序语义的合法性,即类的方法体的校验分析

保证时刻操作数栈与指令代码序列能配合工作

保证跳转指令不会跳转到方法体以外的字节码指令上

保证方法体的类型转换是有效的

符号引用验证:类的常量池中各种符号引用的信息进行匹配性校验

符号引用中通过字符串描述的全限定名是否能找到对应类

指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段

符号引用中的类、字段和方法的访问性是否可被当前类所访问

连接 Linking 验证 Verification

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

是否以magic开头

主次版本号是否在虚拟机处理范围内

常量池中的常量是否有不支持的类型

指向的常量索引值是否有指向不存在常量或不符合类型常量的情况

CONSTANT_Utf8_info的常量是否符合utf8编码规范

Class文件各个部分及文件本身是否有被删除或附加的其他信息

元数据验证:字节码描述的信息进行语义分析

是否有父类

父类是否继承了不允许被继承的类(final的)

如果不是抽象类是否实现了其父类或接口之中要求实现的类

类中字段、方法是否与父类产生矛盾

覆盖了父类的final字段

不符合规范的方法重载
方法参数类型一致返回值类型不一致

字节码验证:通过数据流和控制流分析程序语义的合法性,即类的方法体的校验分析

保证时刻操作数栈与指令代码序列能配合工作

保证跳转指令不会跳转到方法体以外的字节码指令上

保证方法体的类型转换是有效的

符号引用验证:类的常量池中各种符号引用的信息进行匹配性校验

符号引用中通过字符串描述的全限定名是否能找到对应类

指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段

符号引用中的类、字段和方法的访问性是否可被当前类所访问

准备 Preparation

类变量分配空间

类变量分配零值

类常量分配初始值:由类字段的ConstantValue属性进行赋值

解析 Resolution

实际上就是把常量池中的符号引用替换为直接引用的过程

符号引用

在常量池中即非字面量的类型

CONSTANT_Class_info

CONSTANT_Fieldref_info

CONSTANT_Methodref_info

CONSTANT_InterfaceMethodref_info

特征

与虚拟机实现的内存布局无关

引用的目标并不一定已经加载到内存中

由虚拟机Class文件格式规范,因此不同虚拟机能够接受的符号引用格式是确定的

直接引用

表达形式

直接指向目标的虚拟机内存中的指针

相对偏移量

能够定位到目标的句柄

特征

与虚拟机的内存布局直接相关

引用的目标必须已经存在于内存中

同一符号引用在不同虚拟机中的直接引用一般不同,由虚拟机自己制定格式

符号引用解析

类或接口的解析

对CONSTANT_Class_info符号引用的解析

对全限定名的解析

虚拟机加载类D中的类符号引用N为一个类或接口C的直接引用

C不是数组类型

虚拟机将N代表的全限定名传递给D的类加载器来加载C

C被成功加载后(可能是之前已经加载过或者本次执行了首次加载),虚拟机将D中的符号引用N替换为C的直接引用

符号引用验证,如D是否具备对C的访问权限

C是数组类型


虚拟机将N代表的全限定名(如[Ljava.lang.Integer)传递给D的类加载器来加载C(详见数组类加载流程)

D的类加载器先加载C的组件类型(如java.lang.Integer)

虚拟机在方法区生成一个代表了数组维度和组件类型的数组对象

C被成功加载后,虚拟机将D中的符号引用N替换为C的直接引用

符号引用验证,如D是否具备对C的访问权限

字段解析

对CONSTANT_Fieldref_info符号引用的解析

对class_index的解析

对nameAndType_index的解析

虚拟机在类D中加载字段符号引用N为字段F的直接引用

虚拟机在N中指定的类C里寻找字段描述符和N中指定的字段描述符一致的字段F

能找到,就将符号引用N替换为F的直接引用

符号引用验证,如D是否具备对F的访问权限

找不到,在类C实现的接口中按照继承关系从下向上寻找字段描述符和N中指定的字段描述符一致的字段F

能找到就将符号引用N替换为F的直接引用

符号引用验证,如D是否具备对F的访问权限

找不到,在类C继承的父类中按照继承关系从下向上寻找字段描述符和N中指定的字段描述符一致的字段F

能找到就将符号引用N替换为F的直接引用

符号引用验证,如D是否具备对F的访问权限

找不到,抛出java.lang.NoSuchFieldError异常

类方法解析

对CONSTANT_Methodref_info符号引用的解析

对class_index的解析

对nameAndType_index的解析

虚拟机在类D中加载类方法符号引用N为方法M的直接引用

虚拟机在N中指定的类C里寻找方法描述符和N中指定的方法描述符一致的方法M

能找到

class_index指定的类不是接口,就将符号引用N替换为M的直接引用

class_index指定的类是接口,抛出java.lang.IncompatibleClassChangeError异常

符号引用验证,如D是否具备对M的访问权限

找不到,在类C继承的父类中按照继承关系从下向上寻找方法描述符和N中指定的方法描述符一致的方法M

能找到就将符号引用N替换为M的直接引用

符号引用验证,如D是否具备对M的访问权限

找不到,在类C实现的接口中按照继承关系从下向上寻找方法描述符和N中指定的方法描述符一致的方法M

能找到,说明类C是抽象类,抛出java.lang.AbstractMethodError异常(为什么说明C是抽象类呢?C的方法在C中找不到,但是在C实现的接口中找到了,这意味着C实现了接口但是没有实现接口的这个方法,因此C类只可能是抽象类。)

找不到,抛出java.lang.NoSuchMethodError异常

接口方法解析

对CONSTANT_InterfaceMethodref_info符号引用的解析

对class_index的解析

对nameAndType_index的解析

虚拟机在类D中加载接口方法符号引用N为方法M的直接引用

虚拟机在N中指定的接口C里寻找方法描述符和N中指定的方法描述符一致的方法M

能找到

class_index指定的类是C接口,就将符号引用N替换为M的直接引用

class_index指定的类C不是接口,抛出java.lang.IncompatibleClassChangeError异常

符号引用验证,接口方法都是public的所以没有访问权限的问题

找不到,在接口C继承的父接口中按照继承关系从下向上寻找方法描述符和N中指定的方法描述符一致的方法M

能找到就将符号引用N替换为M的直接引用

找不到,抛出java.lang.NoSuchMethodError异常

初始化 Initialization 初始化就是执行()方法的过程 ()

()是编译期生成在Class字节码中的,由编译器自动收集类中的所有类变量的赋值动作和静态代码块static{…}中的语句合并而成

()是类构造器,与实例构造器()不同,虚拟机保证会在调用前先调用其父类的(),因此不需要显式调用父类构造器

父类的()对类变量的赋值操作优先于子类的()执行

()并非必需,如果类中无静态代码块或对类变量的赋值操作,那么编译器可以不生成()方法,Class字节码中也就没有()方法

接口无静态代码块但是可以用类变量赋值操作,因此也会生成方法,但是不需要先调用父接口的()方法,只有父接口的类变量使用时才调用()方法初始化父接口

虚拟机会保证多线程环境下类的()方法可以阻塞地调用,即线程T1调用类C的()方法初始化C的过程中,线程T2会阻塞而无法进入类C的()方法中的

使用 Using 卸载 Unloading

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76792.html

相关文章

  • Java相关

    摘要:本文是作者自己对中线程的状态线程间协作相关使用的理解与总结,不对之处,望指出,共勉。当中的的数目而不是已占用的位置数大于集合番一文通版集合番一文通版垃圾回收机制讲得很透彻,深入浅出。 一小时搞明白自定义注解 Annotation(注解)就是 Java 提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解) 是一个接口,程序可以通过...

    wangtdgoodluck 评论0 收藏0
  • Java编译期优化思维导图

    摘要:本文参考自来自周志明深入理解虚拟机第版,拓展内容建议读者可以阅读下这本书。和构造方法一一对应,是同一概念在两个级别的含义收敛的操作自动保证执行父类的执行语句块初始化类变量字符串加操作替换为或的操作 showImg(https://segmentfault.com/img/remote/1460000016240419?w=3876&h=3614); 本文参考自来自周志明《深入理解Jav...

    sorra 评论0 收藏0
  • 利用MAT分析JVM内存问题,从入门到精通(二)

    摘要:用于列举最近分析过的文件常用功能栏,从左到右依次是概览类直方图支配树查询线程视图报告相关详细功能。针对那些占用堆内存超过整个堆内存大小的组件做一系列的分析,例如保留集合潜在的内存浪费问题等其他问题。 上一篇文章MAT入门到精通(一)介绍了MAT的使用场景和基本概念,这篇文章开始介绍MAT的基本功能,后面还有两篇,一篇是MAT的高级功能,另一篇是MAT实战案例分析。 三、欢迎页 使用MA...

    amuqiao 评论0 收藏0
  • Java程序员:不识Jvm真面目,只缘身在增删查改中

    摘要:编译器只需面向,生成能理解的代码或字节码文件。源文件经编译器,编译成字节码程序,通过将每一条指令翻译成不同平台机器码,通过特定平台运行。涨见识,字节码执行过程分析。解决办法减少默认栈的容量来换取更多的线程支持。 前言 JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的...

    or0fun 评论0 收藏0
  • Java程序员:不识Jvm真面目,只缘身在增删查改中

    摘要:编译器只需面向,生成能理解的代码或字节码文件。源文件经编译器,编译成字节码程序,通过将每一条指令翻译成不同平台机器码,通过特定平台运行。涨见识,字节码执行过程分析。解决办法减少默认栈的容量来换取更多的线程支持。 前言 JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的...

    ivydom 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<