JVM实验二:类加载机制
一、类加载介绍
(1)加载
根据类的全限定名获取类的二进制流;
将类的静态数据结构转换成运行时数据结构;
生成class文件作为方法区的访问入口(个人理解:加载就是将静态的编译完成的class文件加载到方法区)
(2)验证
包括:文件格式验证/元数据验证/字节码验证/符号引用验证
(3)准备
为类变量赋初值
(4)解析
将符号引用转换为直接引用
(5)初始化
给类变量分配内存并赋初始值,执行静态代码块
二、实验---验证对象数组的加载状态
1 public class Singleton { 2 private Singleton() { 3 } 4 5 private static class LazyHolder { 6 static final Singleton INSTANCE = new Singleton(); 7 8 static { 9 System.out.println("LazyHolder."); 10 } 11 } 12 13 public static Object getInstance(boolean flag) { 14 if (flag) return new LazyHolder[2]; 15 return LazyHolder.INSTANCE; 16 } 17 18 public static void main(String[] args) { 19 getInstance(true); 20 System.out.println("----"); 21 getInstance(false); 22 } 23 }
上述的Java代码中,第14行新建LazyHolder对象数组,15行新建LazyHolder对象,接下来验证在执行第14行时LazyHolder类的加载情况
(1)验证是否加载
验证类是否加载只需要添加虚拟机参数 -XX:+TraceClassLoading //会打印加载日志

结论:加载了元素类
(2)验证是否“验证”
java -cp ./asmtools.jar org.openjdk.asmtools.jdis.Main Singleton\$LazyHolder.class > Singleton\$LazyHolder.jasm.1 #将构造方法的栈大小设置为0,本来是1,用于存放this对象,如果存在“验证”阶段,代码将无法通过而爆出异常 awk 'NR==1,/stack 1/{sub(/stack 1/, "stack 0")} 1' Singleton\$LazyHolder.jasm.1 > Singleton\$LazyHolder.jasm java -cp ./asmtools.jar org.openjdk.asmtools.jasm.Main Singleton\$LazyHolder.jasm java -verbose:class Singleton
将字节码故意修改为错误的字节码,构造函数的栈大小设置为0,因为构造函数栈的0号参数默认是this实例对象,因此这样的字节码是无法通过验证的

执行结果显示异常,因此显然此类已经被验证过了
结论:验证了元素类
(3)验证初始化
执行Java代码,结果为:
----
LazyHolder.
显然并没有执行元素类的静态代码块
结论:没有初始化
(4)实验结论
在执行元素类的创建时,例如Object obj = new Object()
显然会执行类的加载、链接、初始化
在执行元素类数组的创建时,例如Object[] objs = new Object[1]
会执行类的加载、链接,但不会执行初始化

浙公网安备 33010602011771号