美文网首页
jvm专题:6.类加载过程

jvm专题:6.类加载过程

作者: 北交吴志炜 | 来源:发表于2019-02-27 17:24 被阅读0次

1.类加载的时机
1)遇到new(常规的new对象),getstatic,putstatic(读取或者设置类变量)或invokestatic(调用类方法)这四条字节码指令时,如果类没有初始化,会触发其初始化。
2)使用java.lang.reflect包对某个类进行反射调用的时候,。。。。。
3)当初始化一个类时,如果其父类还没有初始化,则会先触发其父类的初始化。
4)虚拟机启动时,用户需要指定一个main方法入口,虚拟机会先初始化其对用的类。
5)当使用jdk1.7以上的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokestatic的方法句柄,并且这个方法句柄对应的类没有初始化,。。。。。
第五点不是很明白,后续会update。

虚拟机规范中,定义,有且仅有这5种情况会触发类的初始化,比如子类调用父类的静态变量,不会触发子类的初始化。

2.类加载的过程
加载,验证,准备,解析,初始化,使用,卸载


1)加载:
虚拟机进行类加载的最终结果是在内存中产生一个java.lang.Class对象,作为访问这个类的入口,其基础是类的二进制流。这个二进制流从何而来呢?
可以从zip包中来,比如jar包,war包,EAR等
可以从网络中来,比如Applet
可以运行时计算生成,比如动态代理生成的proxy类
可以从其他文件中来,比如jsp
可以从数据库中读取(这是一个骚操作)


2)验证
验证的目的是防止恶意代码导致虚拟机崩溃或异常,验证阶段包含四个动作

@1 文件格式验证,主要针对字节流
是否以OXCAFEBABE开头
主、次版本号是否在当前虚拟机处理范围
常量池的常量中是否有不被支持的常量类型(不明白,后续要update)
指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量 ---
CONSTANT_Utf8_info型的常量中是否有不符合utf-8编码的数据---
CLASS文件中各个部分以及文件本身是否有被删除的或附加的其他信息---

@2 元数据验证
这个类是否有父类(除了Object)
这个类的父类是否继承了不被允许继承的类(final 修饰的类)
如果这个类不是抽象类,是否实现了其父类或者接口中要求实现的所有方法
类中的方法或字段是否与父类中的冲突(例如覆盖了父类中的final字段,或者出现不符合规则的方法重载,例如方法参数都一致,但返回值不一致)

@3 字节码验证
通过数据流和控制流分析,确定程序语义是合法的,符合逻辑的,主要针对方法体
操作数栈中放入int,使用时按long来载入本地变量表
保证跳转指令不会跳转到方法体外的字节码指令上。 ------
保证合法的类型转换,子类可以转换为父类,但是不能将父类对象转换为子类。或者不相干的类

@4 符号引用验证
符号引用中通过字符串描述的全限定名是否能找到相应的类
在指定的类中是否存在符合方法字段描述以及名称描述的方法和字段
符号引用中的类,字段,方法的访问可见性是否可以被当前类访问

符号引用的目的是确保解析动作可以正常进行,这个阶段验证失败会抛出一些ERROR,都是IncompatibleClassChangeError的子类
java.lang.IllegalAccessError 访问权限不允许访问
java.lang.NoSuchFieldError 类定义中没有相关的字段
java.lang.NoSuchMethodError 没有相关的方法


3)准备

为类变量分配内存,设置初始值。
比如有类变量 public static int value =123,那么准备阶段之后,这个值会是0,真正赋值123是在初始化阶段发生的
不同数据类型,初始值见


11111.png

如果类变量被final 修饰,即public static final int value =123 ,那么准备阶段就会将该变量设为123


4)解析
解析阶段主要是虚拟机将常量池内的符号引用替换为直接引用的过程
符号引用:以一组符号来描述所引用的目标,符号可以是任何的字面量,只要可以无歧义的定位到目标即可,引用的目标不一定已经加载到内存中。
直接引用:直接指向目标的指针,相对偏移量或者是一个能间接定位到目标的句柄,如果有了直接引用,目标必定已经在内存中存在
解析主要包括
1.类或接口的解析
比如在类D中,有一个符号引用N,需要解析为一个类或者接口C的直接引用
如果C是不是数组类型,那么虚拟机会把代表N的全限定名传递给D的类加载器去加载类C,那么在加载的过程中,由于元数据验证,字节码验证的需要,可能触发连锁的类加载动作。
如果C是数组类型,并且数据的元素是对象,那么会触发元素类的加载动作
在解析完成之前还需要进行符号引用验证,判断访问权限

 2.字段解析
 字段解析之前会对字段所属的类或者接口进行解析,字段解析的过程是从当前类开始,按照继承关系,从下往上递归搜索其父类,匹配则返回。否则,查找失败,抛出NosuchFieldError异常。匹配成功,同样要做访问权限验证

3.类方法解析
4.接口方法解析

5)初始化
为类变量赋值
执行static块

相关文章

网友评论

      本文标题:jvm专题:6.类加载过程

      本文链接:https://www.haomeiwen.com/subject/jepzyqtx.html