• 【JVM】类加载机制:分析与验证


    一、加载

    • 将类的字节码载入方法区中,内部采用 C++ 的 instanceKlass 描述 java 类。它的重要 field 有:
      • _java_mirror : java 的类镜像,例如对 String 来说,就是 String.class,作用是把 klass 暴露给 java 使用
      • _super :父类
      • _fields :成员变量
      • _methods :方法
      • _constants :常量池
      • _class_loader :类加载器
      • _vtable :虚方法表
      • _itable :接口方法表
    • 如果这个类还有父类没有加载,先加载父类
    • 加载和链接可能是交替运行的

    注意

    • instanceKlass 这样的【元数据】是存储在方法区(1.8 后的元空间内),但 _java_mirror 是存储在堆中
    • 可以通过前面介绍的 HSDB 工具查看

    在这里插入图片描述

    二、链接

    1)验证

    验证类是否符合 JVM规范,安全性检查

    • 修改 Verify.java 的魔数:将 cafebabe 修改为 cafebaby

      在这里插入图片描述

    • 解释执行结果:类格式错误

      PS F:\software\IDEA\JavaProjects\JvmTest\target\classes\org\example\classLoading\link> java Verify
      Error: A JNI error has occurred, please check your installation and try again
      Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1128351301 in class file Verify
              at java.lang.ClassLoader.defineClass1(Native Method)
              ...
      
      • 1
      • 2
      • 3
      • 4
      • 5

    2)准备

    为 static 变量分配空间,设置默认值

    • JDK 7 之前:static 变量 存储于 instanceKlass 末尾
    • JDK 7 开始:static 变量 存储于 _java_mirror(类.class对象) 末尾
    • 注意:final 类型的 static 变量
      • 基本类型常量、字符串常量:编译阶段值就确定了,赋值操作在本阶段完成
      • 引用类型常量:赋值操作在 初始化阶段 完成

    3)解析

    将自己在其他类的常量池中的符号引用解析为直接引用

    类A没有解析为直接引用

    public class Analysis{
        public static void main(String[] args) throws IOException {
            //1.访问类A的静态变量(基本类型、字符串)不会导致类A的初始化(解析)
            System.out.println(A.a);
            System.in.read();
        }
    }
    class A{
        final static int a=1;
        static int b=1;
        static {
            System.out.println("init");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 运行程序

    2. 执行命令行命令,查看当前进程id

      PS F:\software\IDEA\JavaProjects\JvmTest> jps
      13816 Analysis
      ...
      
      • 1
      • 2
      • 3
    3. 进入 jdk 安装目录,执行命令打开 HSDB工具

      F:\software\Java\jdk1.8.0_333>java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
      
      • 1
    4. 将 HSDB工具 链接到当前进程

      在这里插入图片描述

    5. 找到 Analysis 类的常量池,查看类A的引用

    在这里插入图片描述

    类A解析为直接引用

    public class Analysis{
        public static void main(String[] args) throws IOException {
            //2.访问类变量导致初始化
            System.out.println(A.b);
            System.in.read();
        }
    }
    class A{
        final static int a=1;
        static int b=1;
        static {
            System.out.println("init");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 运行程序

    2. 执行命令行命令,查看当前进程id

      PS F:\software\IDEA\JavaProjects\JvmTest> jps
      4768 Analysis
      ...
      
      • 1
      • 2
      • 3
    3. 进入 jdk 安装目录,执行命令打开 HSDB工具

      F:\software\Java\jdk1.8.0_333>java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
      
      • 1
    4. 将 HSDB工具 链接到当前进程

      在这里插入图片描述

    5. 找到 Analysis 类的常量池,查看类A的引用

      在这里插入图片描述

    三、初始化

    1)()V 方法

    初始化即调用 ()V ,虚拟机会保证 ()V 的线程安全

    2)发生的时机

    导致类初始化的情况:

    • main 方法所在的类
    • new
    • 首次访问类的 静态变量、静态方法
    • 子类初始化,如果父类还没初始化
    • Class.forName(String)

    不会导致类初始化的情况 :

    • 类加载器的 loadClass 方法 :加载阶段
    • Class.forName(String,false) :加载阶段
    • 创建该类的数组不会触发初始化 :加载阶段
    • 访问 类.class :加载阶段
    • 访问类的 静态常量(基本类型和字符串) :链接-准备阶段

    验证:导致类初始化的情况

    public class Init {
        static {
            //1.main方法所在类。首先被初始化
            System.out.println("1.init:main方法所在类");
        }
        public static void main(String[] args) throws ClassNotFoundException {
            //2.new
            A newTest=new A();
            //3.子类初始化
            //4.访问类的 静态变量、静态方法
            int a=B.b;
            //5.Class.forName(String)
            Class.forName("org.example.classLoading.link.D");
        }
    }
    class A{
        static {
            System.out.println("2.init:new的类");
        }
    }
    class B extends C{
        static int b=1;
        static {
            System.out.println("4.init:访问类的静态变量、静态方法");
        }
    }
    class C{
        static {
            System.out.println("3.init:子类初始化");
        }
    }
    class D{
        static {
            System.out.println("5.init:Class.forName(String)");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    1.init:main方法所在类
    2.init:new的类
    3.init:子类初始化
    4.init:访问类的静态变量、静态方法
    5.init:Class.forName(String)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    验证:不会导致类初始化的情况

    public class Init {
        public static void main(String[] args) throws ClassNotFoundException {
            ClassLoader classLoader = Init.class.getClassLoader();
            //1.类加载器的 loadClass 方法 :加载阶段
            classLoader.loadClass("org.example.classLoading.link.A");
            //2.Class.forName(String,false) :加载阶段
            Class.forName("org.example.classLoading.link.A",false,classLoader);
            //3.创建该类的数组不会触发初始化 :加载阶段
            A[] arr=new A[2];
            //4.访问 类.class :加载阶段
            Class<A> clazz = A.class;
            //5.访问类的 静态常量(基本类型和字符串) :链接-准备阶段
            int a=A.a;
        }
    }
    class A{
        static final int a=1;
        static {
            System.out.println("init A");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    Process finished with exit code 0
    
    • 1
  • 相关阅读:
    【Pytorch深度学习实战】(6)递归神经网络(RNN)
    第2章 传输网
    Django后端开发——中间件
    k8s核心组件
    HBase 基础结构
    【Javascript】定时器
    C---流
    暑期JAVA学习(31)多线程的创建
    Vector | Graph:蚂蚁首个开源Graph RAG框架设计解读
    SAP CRM 模块:概述,体系结构
  • 原文地址:https://blog.csdn.net/weixin_43401592/article/details/128019881