JAVA类加载器的原理(记录)

78 阅读2分钟

类加载器是什么

在我们执行一个正常的main函数之后,其实要做的第一件事加载当前这个main函数所在的类,在此期间所碰到的比如 new Student()或者静态方法的调用以及字段赋值等等这些操作都会先进行初始化相应的类。所在类加载器的作用就是将我们在执行过程中所碰到类加载到方法区中,然后将该类的class的静态数据结构挂载到其classloader上(将符号引用替换换为实际引用),方便后续的针对当前类的静态数据结构的调用。

类加载器的各个阶段

类的加载(全貌图)

类的链接

  1. 字节码验证

做字节码结构正确性的验证。比如if_icmpeg字节码判断两个整数相等并做结果跳转

  1. 字节码重写
    1. 重写finalize方法

当某个类重写finalize方法是,会在类加载的时候将最后一条字节码return重写器重写为_return_register_finalizer,在虚拟机执行的时候如果发现是非标准的_return_register_finalizer,则会插入机器指令判断当前方法是否重写finalize,如果重写将会调用java.lang.ref.Finalizer的register()方法。

  1. 方法连接
    1. 在我们学习jvm的时候,经常听说jni,也就是java native interface,由于HotSpotVM的执行模式是解释器与JIT编译器混合的模式,当一个Java方法/循环被探测到是热点的时候,即执行了很多次的时候,就可能使用JIT编译器编译后然后通过解释器切换到执行器然后再执行它,这里有两个疑问:
      1. 怎么就能检测到某个方法是否是热点方法

在JVM中使用oops/method.cpp表示JVM层的Java方法,在此方法中就包含了JNI中的解释器、编译器的代码入口和以及重要的用于统计方法性能的数据。在字节码层面插入计算逻辑来进行检测。

  2. 怎么就能切换解释器和执行器的逻辑

简单理解的话,就是在虚拟机层面有定点入口,当前方法如果被编译为机器码,则将当前方法入口的地址设置为机器码的地址,如果未进行编译,则使用解释器入口进行执行,也就是常说的方法区。

  1. 初始化vtable(虚表)和itable(接口表)
  2. 链接完成(set_init_state)

类的初始化

  1. 类的构造器的初始化

类的构造器的执行和静态构造器的执行 以及方法的执行

  1. 重定义类(核心原理利用JVMTL进行类的重定义) skywalking的agent就是基于类的指令集进行类的重载的