【深入理解Java虚拟机】虚拟机类加载机制:类的生命周期&类加载的过程
今日一句: “我与春风皆过客”
1.类加载的时机
1.1 类的生命周期
一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,经历7个阶段。
1.2 必须立即对类初始化的6种情况
//书上有 还没写
2.类加载的过程
2.1 加载
加载类时要做的3件事
类的二进制字节流不一定从某个Class文件中获取,这点给虚拟机使用者很大的发挥空间。
加载后
class数据结构存储在元空间(jdk8之后),Class实例存储在堆中。
数组类的加载
1.引用类型:如果数组的组件类型(数组去掉一个维度的类型)是引用类型,那就递归采用加载过程去加载这个组件类型。// 数组将被标识在加载该组件类型的类加载器的类名称空间上。
2.非引用类型:组件类型是基本类型,Java虚拟机将会把数组标记为与引导类加载器关联。
3.可访问性:数组类的可访问性与它的组件类型的可访问性一致。如果组件类型不是引用类型,可访问性将默认为public。
2.2 连接
2.2.1 验证
验证目的:保证字节码合法。
验证环节:
1.文件格式验证:是否符合Class文件格式的规范
2.元数据验证:对字节码描述的信息进行语义分析
3.字节码验证:确定程序语义是合法的、符合逻辑的
4.符号引用验证:确保解析行为能正确执行
如果代码已经被反复使用和验证过,在生产环境的实施阶段就可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
2.2.2 准备
准备目的:正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。
初始值一般为0值。
但静态常量,如static final int value=123,在编译时Javac就会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123。
(从概念上讲,这些变量所使用的内存都应当在方法区中进行分配。但这只是逻辑上的概念。见书p272)
2.2.3 解析
解析目的:将常量池内的符号引用替换为直接引用
String的解析:
3.初始化
类的初始化阶段是类加载过程的最后一个步骤,直到初始化阶段,Java虚拟机才真正开始执行类中编写的Java程序代码,将主导权移交给应用程序。
初始化阶段的重要工作是执行< clinit >()方法:
说明:
1.在加载一个类之前,会先尝试加载父类。先执行父类的clinit方法,所以父类的static块先执行。
2.Java编译器并不会为所有类生成clinit方法,在以下几种情况就不会生成:
①一个类中既没有类变量,也没有静态代码块
②一个类中声明类变量,但没有明确使用类变量的初始化语句以及静态代码块语句来执行初始化操作时
③一个类中包含static final修饰的基本数据类型的字段,这些类字段初始化语句采用编译时常量表达式
一个结论:
使用static final修饰的基本类型或String,但显式赋值中涉及方法或构造器调用,在初始化环节进行。
…不涉及调用,在准备阶段进行。