《深入理解Java虚拟机:JVM高级特性与最佳实践》第2版
第6章 类文件结构
41. 控制转移指令
让JVM有条件或无条件地从指定的位置指令继续执行程序。
分为处理 int 和 reference 类型的条件分支比较,还有检测 null 值的指令。
对于 boolean、byte、char、short 都是使用 int 类型的比较指令完成;对于 long、float、double 类型则会先执行相应类型的比较运算指令,返回一个整型到操作数栈,再执行 int 类型的条件分支比较操作完成整个分支跳转。
42. 同步指令
用 synchronized 实现同步,通过管程 Monitor 来支持。
方法级的同步无需字节码指令控制,执行线程先成功持有管程,然后执行方法,最后方法完成时释放管程。
代码块同步需要 monitorenter 和 moniterexit 指令支持,编译时在字节码插入这两条指令。 monitorenter 和 moniterexit 要成对出现,因此编译器自动生成一个异常处理器,确保处理所有异常,用来执行 monitorexit。
第7章 虚拟机类加载机制
43. 类的生命周期
加载、验证、准备、解析、初始化、使用、卸载。
其中验证、准备、解析统称为连接。
加载、验证、准备、初始化、卸载这5个阶段的顺序是确定的,但不是串行的。换句话说,这5个阶段通常是交叉进行。另外,解析可以在初始化之后再开始,这是为了运行时绑定(动态绑定或晚期绑定)。
44. 类加载时机
Java虚拟机规范并没有强行约束类的加载时机,但是规定了有且只有5种情况必须立即对类初始化(自然加载、验证、准备在此之前开始)。
(1)遇到 new、getstatic、putstatic 或 invokestatic 字节码指令,如果类没有初始化则触发;
(2)使用 java.lang.reflect 包的方法对类进行反射调用,如果类没有初始化则触发;
(3)当初始化一个类的时候,如果发现父类还没有进行初始化,则先触发父类初始化;
注:接口在初始化时,不要求父接口全部完成初始化,只有在使用到父接口的时候才会初始化。
(4)虚拟机启动时要执行的主类;
(5)当使用JDK1.7时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个句柄对应的类没有初始化,则触发初始化。
45. 被动引用不会触发类的初始化
上述5种场景是对一个类的主动引用。被动引用举例:
(1)通过子类引用父类的静态字段,只会触发父类的初始化而不会触发子类的初始化;
(2)定义类的数组时用 newarray 指令触发而不是new;
(3)常量属性在编译阶段存入调用类的常量池种,本质上没有直接引用到定义常量的类,因此不会触发该常量所属类的初始化。
接下来要具体学习类的加载过程了~
待续...
网友评论