HotSpot虚拟机类加载机制类的生命周期什么叫做类加载?类加载的定义: JVM把形容类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终变成能够被JVM间接应用的Java类型(因为能够动静产生,这里的Class文件并不是具体存在磁盘中的文件,而是二进制数据流)
一个类型被加载到内存应用 到 完结卸载出内存,它的生命周期分为7个阶段: 加载->验证->筹备->解析->初始化->应用->卸载
其中重要阶段个别的开始程序: 加载->验证->筹备->解析->初始化
验证,筹备,解析合起来又称为连贯所以也能够是加载->连贯->初始化
留神这里的程序是个别的开始程序,并不一定是执行完某个阶段完结后才开始执行下一个阶段,也能够是执行到某个阶段的中途就开始执行下一个阶段
还有种非凡状况就是解析可能在初始化之后(因为Java运行时的动静绑定)
根本数据类型不须要加载,援用类型才须要被类加载
类加载阶段接下来将对这五个阶段进行具体介绍
Loading加载加载的作用通过这个类的全限定名来查找并加载这个类的二进制字节流
JVM通过文件系统加载某个class后缀文件读取jar包中的类文件数据库中类的二进制数据应用相似HTTP等协定通过网络加载运行时动静生成Class二进制数据流将这个类所代表的动态存储构造(动态常量池)转化为办法区运行时数据结构(运行时常量池)在堆中创立这个类的Class对象,这个Class对象是对办法区拜访数据的"入口"
堆中实例对象中对象头的类型指针指向它这个类办法区的类元数据对于加载能够由JVM的自带类加载器来实现,也能够通过开发人员自定义的类加载器来实现(实现ClassLoader,重写findClass())留神
数组类是间接由JVM在内存中动静结构的,数组中的元素还是要靠类加载器进行加载反射正是通过加载创立的Class对象能力在运行期应用反射Verification验证验证的作用
确保要加载的字节码符合规范,避免危害JVM平安
验证的具体划分
文件格式验证
目标: 保障字节流能正确解析并存储到办法区之内,格局上合乎Java类型信息
验证字节流是否合乎Class文件格式标准(比方Class文件主,次版本号是否在以后虚拟机兼容范畴内...)
元数据验证
目标: 对类的元数据信息进行语义验证
元数据:简略的来说就是形容这个类与其余类之间关系的信息
元数据信息验证(举例):
这个类的父类有没有继承其余的最终类(被final润饰的类,不可让其余类继承)若这个类不是抽象类,那这个类有没有实现(形象父类)接口的所有办法字节码验证(验证中最简单的一步)
目标: 对字节码进行验证,保障校验的类在运行时不会做出对JVM危险的行为
字节码验证举例:
类型转换无效: 子类转换为父类(平安,无效) 父类转换为子类(危险)进行算术运算,应用的是否是雷同类型指令等符号援用验证
产生在解析阶段前:符号援用转换为间接援用
目标: 保障符号援用转为间接援用时,该类不短少它所依赖的资源(外部类),确保解析能够实现
验证阶段是一个十分重要的阶段,但又不肯定要执行(因为许多第三方的类,本人封装的类等都被重复"试验"过了)
在生产阶段能够思考敞开 -Xverify:none以此来缩短类加载工夫
Preparation筹备筹备阶段为类变量(动态变量)分配内存并默认初始化
分配内存
逻辑上应该调配在办法区,然而因为hotSpot在JDK7时将字符串常量,动态变量挪出永恒代(放在堆中)实际上它应该在堆中默认初始化
类变量个别的默认初始化都是初始化该类型的零值
类型零值byte(byte)0short(short)0int0long0Lfloat0.0Fdouble0.0booleanfalsechar'\u0000'referencenull非凡的类变量的字段属性中存在ConstantValue属性值,会初始化为ConstantValue所指向在常量池中的值只有被final润饰的根本类型或字面量且要赋的值在常量池中才会被加上ConstantValue属性
Resolution解析解析的作用
将常量池中的常量池中符号援用替换为间接援用(把符号援用代表的地址替换为实在地址)
符号援用
应用一组符号形容援用(为了定位到指标援用)与虚拟机内存布局无关还是符号援用时指标援用不肯定被加载到内存间接援用
间接执行指标的指针,绝对偏移量或间接定位指标援用的句柄与虚拟机内存布局相干解析间接援用时指标援用曾经被加载到内存中并未规定解析的工夫
能够是类加载时就对常量池的符号援用解析为间接援用
也能够在符号援用要应用的时候再去解析(动静调用时只能是这种状况)
同一个符号援用可能会被解析屡次,所以会有缓存(标记该符号援用曾经解析过),屡次解析动作都要保障每次都是雷同的后果(胜利或异样)类和接口的解析当咱们要拜访一个未解析过的类时
把要解析的类的符号援用 交给以后所在类的类加载器 去加载 这个要解析的类解析前要进行符号援用验证,如果以后所在类没有权限拜访这个要解析的类,抛出异样IllegalAccessError字段的解析解析一个从未解析过的字段
先对此字段所属的类(类, 抽象类, 接口)进行解析而后在此字段所属的类中查找该字段简略名称和描述符都匹配的字段,返回它的间接援用
如果此字段所属的类有父类或实现了接口,要自下而上的寻找该字段找不到抛出NoSuchFieldError异样对此字段进行权限验证(如果不具备权限抛出IllegalAccessError异样)确保JVM取得字段惟一解析后果
如果同名字段呈现在父类,接口等中,编译器有时会更加严格,间接回绝编译Class文件
办法的解析解析一个从未解析过的办法
先对此办法所属的类(类, 抽象类, 接口)进行解析而后在此办法所属的类中查找该办法简略名称和描述符都匹配的办法,返回它的间接援用
如果此办法所属类是接口间接抛出IncompatibleClassChangeError异样如果此办法所属的类有父类或实现了接口,要自下而上的寻找该办法(先找父类再找接口)如果在接口中找到了,阐明所属类是抽象类,抛出AbstractMethodError异样(本身找不到,父类中找不到,最初在接口中找到了,阐明他是抽象类),找不到抛出NoSuchMethodError异样对此办法进行权限验证(如果不具备权限抛出IllegalAccessError异样)接口办法的解析解析一个从未解析过的接口办法
先对此接口办法所属的接口进行解析而后在此接口办法所属的接口中查找该接口办法简略名称和描述符都匹配的接口办法,返回它的间接援用
...