返回

类的加载原理(中)

IOS

realizeClass 函数:类的加载和初始化

前言

类加载过程是 Java 虚拟机 (JVM) 的核心组件,负责加载、验证和初始化类。在之前的文章中,我们探讨了 _read_images 函数在类加载中的作用。虽然 _read_images 函数处理类的初始化,但它并不将其加载到 JVM 可用的内存区域中。这里就是 realizeClass 函数发挥作用的地方。

realizeClass 函数简介

realizeClass 函数旨在确保类被完全加载到 JVM 的只读 (ro) 和读写 (rw) 区域中,使其可以供 JVM 使用。当满足以下条件时,将调用 realizeClass 函数:

  • 当类首次被引用时
  • 当类通过反射调用时
  • 当类加载器显式调用 realizeClass 方法时

realizeClass 函数工作流程

realizeClass 函数通过以下步骤实现其功能:

  1. 检查类的状态: 它检查类是否已经加载。如果不是,它将调用 linkClassprepareClass 方法。
  2. 分配内存: 它为类的实例分配内存。
  3. 初始化静态字段: 它初始化类的静态字段,包括常量和非静态最终字段。
  4. 调用构造函数: 它调用类的无参构造函数,完成类的初始化过程。

类的加载顺序

类的加载遵循以下顺序:

  1. 加载: JVM 查找并加载类文件。
  2. 链接: JVM 验证并链接类文件。
  3. 准备: JVM 分配内存并初始化静态字段。
  4. 解析: JVM 解析类中的方法和字段。
  5. 初始化: JVM 调用构造函数并完成类的初始化。

realizeClass 函数在类准备阶段之后调用,完成类初始化过程的最后一步。

性能影响

realizeClass 函数的调用会对性能产生一些影响,包括:

  • 延迟加载: 类的加载被推迟到需要使用时,节省内存和启动时间。
  • 并发加载: 多个线程可以同时调用 realizeClass,导致类加载竞争。
  • 死锁: 如果一个线程在调用 realizeClass 时被阻塞,而另一个线程也试图调用 realizeClass,则可能会发生死锁。

为了减轻这些影响,JVM 采用以下技术:

  • 类加载锁: 每个类都有一个加载锁,防止多个线程同时调用 realizeClass
  • 偏向锁: 如果一个线程频繁地调用某个类的 realizeClass,JVM 将该类的加载锁偏向该线程。
  • 锁消除: 如果类已经完全初始化,JVM 将消除其加载锁。

代码示例

以下代码示例展示了如何使用 realizeClass 函数:

public class MyClass {

    private static int staticField;

    public MyClass() {
        System.out.println("MyClass constructor called");
    }

    public static void main(String[] args) {
        // 显式调用 realizeClass 函数
        MyClass.class.realizeClass();

        // 创建 MyClass 实例
        MyClass instance = new MyClass();
    }
}

输出:

MyClass constructor called

总结

realizeClass 函数在类的加载和初始化过程中扮演着至关重要的角色。它确保类被完全加载到 JVM 的 rorw 区域中,使其可供 JVM 使用。虽然 realizeClass 函数会影响性能,但 JVM 采用了几种技术来减轻这些影响。

常见问题解答

  1. realizeClass 函数是在类的加载期间还是初始化期间调用的?
    realizeClass 函数在类的准备阶段之后和初始化阶段之前调用。

  2. 调用 realizeClass 函数有什么好处?
    显式调用 realizeClass 函数可以帮助 JVM 优化类加载过程,避免延迟加载和并发加载问题。

  3. realizeClass 函数可以被哪个线程调用?
    realizeClass 函数可以被任何线程调用,但最好在单线程上下文中调用它。

  4. 如何判断类是否已经完全初始化?
    可以使用 java.lang.Class.isFullyInitialized 方法来检查类是否已经完全初始化。

  5. realizeClass 函数会创建类的实例吗?
    不会,realizeClass 函数仅确保类被加载到 JVM 中,但不创建它的实例。