异常将上下文初始化事件发送到类的侦听器实例_深入浅出JVM性能调优——JVM内存( 九 )


加载阶段会把 Class 常量池中的各项常量存放到运行时常量池中(下图中的常量池只挑选了部分常量来展示) 。加载阶段的最终产品就是 Class 类的实例对象,它成为程序与方法区内部数据结构之间的入口,可以通过这个 Class 实例来获得类的信息、方法、字段、类加载器等等 。
在装载过程中,虚拟机还会确认装载类的所有超类是否都被装载了,根据 super class 项解析符号引用,这就会导致超类的装载、连接和初始化 。
3、验证
这一阶段的目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全 。
验证阶段会完成下面四个阶段的检验:
4、准备
准备阶段是为类中定义的变量(即静态变量,被修饰的变量)分配内存并设置类变量初始值的阶段,初始值是指这个数据类型的零值,而赋值的过程是放在 方法中,在初始化阶段执行的 。注意实例变量是在创建实例对象时才初始化值的 。
基本数据类型的零值:
准备阶段还会为常量字段(final 修饰的常量,即字段表中有属性的字段)分配内存并直接赋值为定义的字面值 。
User 类经过准备阶段后:
5、解析
解析过程就是根据符号引用查找到实体,再把符号引用替换成一个直接引用的过程 。因为所有的符号引用都保存在常量池中,所以这个过程常被称作常量池解析 。
1)静态解析与动态连接:
所有方法调用的目标方法在Class文件里面都是一个常量池中的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数 。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析 。另外一部分将在运行期间用到时转化为直接引用,这部分称为动态连接 。
静态解析的前提是:方法在程序真正运行之前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的 。这类方法包含 静态方法、私有方法、实例构造器、父类方法以及被 final 修饰的方法,这5种方法调用会在类加载的时候就把符号引用解析为该方法的直接引用(有可能是在初始化的时候去解析的) 。
动态连接这个特性给Java带来了更强大的动态扩展能力,比如使用运行时对象类型,因为要到运行期间才能确定具体使用的类型 。这也使得Java方法调用过程变得相对复杂,某些调用需要在类加载期间,甚至到运行期间才能确定目标方法的直接引用 。
2)符号引用解析:
对于符号引用类型如 、fo、nfo 等,会查找到对应的类型数据、方法地址、字段地址的直接引用,然后将符号引用替换为直接引用 。
对于_info 类型指向的字面量,虚拟机会检查字符串常量池中是否已经有相同字符串的引用,有则替换为这个字符串的引用,否则在堆中创建一个新的字符串对象,并将对象的引用放到字符串常量池中,然后替换常量池中的符号引用 。
对于数值类型的常量,如 、o,并不需要解析,虚拟机会直接使用那些常量值 。
6、初始化
直到初始化阶段,Java虚拟机才真正开始执行类中编写的Java程序代码,初始化阶段就是执行类构造器 方法的过程 。
1) 方法:
2)User 类初始化后:
一个类被装载、连接和初始化完成后,它就随时可以使用了 。程序可以访问它的静态字段,调用它的静态方法,或者创建它的实例 。
7、即时编译
初始化完成后,类在调用执行过程中,执行引擎会把字节码转为机器码,然后在操作系统中才能执行 。在字节码转换为机器码的过程中,虚拟机中还存在着一道编译,那就是即时编译 。