类加载阶段
加载: 将类的字节码载入方法区(元空间jdk8)中
其中重要属性:
super父类,fields成员变量,methods方法,constants常量池
class_loader类加载器,vtable虚方法表,itable接口方法表
java_mirror: java的类镜像,如对应String:作用是将Klass暴露给java使用
如果有父类没有加载,则先加载父类
加载和链接可能是交替运行的
以上都是元数据,叫instanceKlass,存在元空间(jdk8)中,但java_mirror存在堆中
加载元数据的同时,会在堆中加载一个java_mirror镜像
链接: 分为三个步骤:
验证: 验证类是否符合jvm规范,安全性检查
准备: 为static变量分配空间,设置默认值(jdk8),和类对象一起存在堆中
静态变量jdk7前存在instanceKlass末尾,jdk7后再java_mirror末尾
静态变量分配空间和赋值是两个步骤,分配空间在准备阶段,赋值在初始化阶段
若静态变量是final的基本类型,那编译时值就确定了,赋值在准备阶段完成
若静态变量是final的引用类型,那赋值在初始化阶段完成
解析: 将常量池中的符号引用解析为直接引用
符号引用: 以字符串形式描述的引用,可以是类名、字段名、方法名等,
只要能唯一定位到目标即可。
直接引用: 直接指向目标的指针、偏移量或句柄,
与虚拟机的内部数据结构和内存布局有关
初始化: 初始化就是调用<init>()V,虚拟机会保证这个类的构造方法的线程安全
初始化阶段只会在第一次主动使用该类时触发,主动使用包括以下六种情况:
创建类实例、访问类或接口的静态变量、
调用类或接口的静态方法、反射调用类或接口、
初始化子类或实现接口、启动 Java 程序时指定主类 。
初始化发生的时机: 类初始化时懒惰的
main方法所在类会首先初始化
首次访问类的静态变量或静态方法时,引发初始化
子类初始化,如果父类没有初始化,引发父类初始化
子类访问父类的静态变量时,只会触发父类初始化
CLass.forName时会引发初始化
new会导致初始化
不会引发初始化的情况
访问类的static final静态常量(基本类型和字符串)不会触发初始化
类对象.class不会触发初始化
创建该类的数组不会触发初始化
类加载器的loadClass方法
Class.forName的参数2为false时
使用(Using):
类加载后的正常状态,指程序通过该类创建对象或调用方法等操作,实现业务逻辑。
卸载(Unloading):
类加载的最后一个阶段,指一个类不再被任何地方引用时,
虚拟机就会将其从方法区中清除,释放内存空间。
卸载阶段由垃圾回收器负责执行。