在类的连接之前要保证对类进行了解析,例如初始化一个类时会调用initialize_class()方法,实现如下:
static void initialize_class(Symbol* class_name, TRAPS) { Klass* klass = SystemDictionary::resolve_or_fail(class_name, true, CHECK); InstanceKlass::cast(klass)->initialize(CHECK); }
在类的初始化过程中,首先要调用SystemDictionary::resolve_or_fail()方法保证类被正确装载,如果类没有被装载,那么最终会调用到ClassFileParser::parseClassFile()方法装载类,并通过创建ConstantPool、Method、InstanceKlass等对象将元数据保存到HotSpot中。然后在调用的initialize()方法中会间接调用InstanceKlass::link_class_impl()方法进行类的连接。InstanceKlass::link_class_impl()方法的实现如下:
bool InstanceKlass::link_class_impl(instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { // return if already verified // 通过_init_state属性的值来判断类是否已经验证过 if (this_oop->is_linked()) { return true; } JavaThread* jt = (JavaThread*)THREAD; // 在连接子类之前先连接父类 // link super class before linking this class instanceKlassHandle super(THREAD, this_oop->super()); if (super.not_null()) { if (super->is_interface()) { // check if super class is an interface return false; } link_class_impl(super, throw_verifyerror, CHECK_false); // 递归调用此方法进行连接操作 } // 连接该类实现的所有接口 // link all interfaces implemented by this class before linking this class Array<Klass*>* interfaces = this_oop->local_interfaces(); int num_interfaces = interfaces->length(); for (int index = 0; index < num_interfaces; index++) { HandleMark hm(THREAD); instanceKlassHandle ih(THREAD, interfaces->at(index)); link_class_impl(ih, throw_verifyerror, CHECK_false); // 递归调用此方法进行连接操作 } // in case万一 the class is linked in the process of linking its superclasses if (this_oop->is_linked()) { return true; } // verification & rewriting 验证和重写 { oop init_lock = this_oop->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // rewritten will have been set if loader constraint error found // on an earlier link attempt // don't verify or rewrite if already rewritten if (!this_oop->is_linked()) { if (!this_oop->is_rewritten()) { { // 进行字节码验证 bool verify_ok = verify_code(this_oop, throw_verifyerror, THREAD); if (!verify_ok) { return false; } } // Just in case a side-effect of verify linked this class already // (which can sometimes happen since the verifier loads classes // using custom class loaders, which are free to initialize things) // 可能有时候会在验证的过程中导致类已经被连接,不过并不会进行类的初始化 if (this_oop->is_linked()) { return true; } // 重写类 // also sets rewritten this_oop->rewrite_class(CHECK_false); } // end rewritten // 完成类的重写后进行方法连接 // relocate jsrs and link methods after they are all rewritten this_oop->link_methods(CHECK_false); // Initialize the vtable and interface table after // methods have been rewritten since rewrite may fabricate(编造; 捏造) new Method*s. // also does loader constraint checking // 初始化vtable和itable if (!this_oop()->is_shared()) { ResourceMark rm(THREAD); klassVtable* kv = this_oop->vtable(); kv->initialize_vtable(true, CHECK_false); klassItable* ki = this_oop->itable(); ki->initialize_itable(true, CHECK_false); } // 将类的状态标记为已连接状态 this_oop->set_init_state(linked); }// end linked }// end verification & rewriting return true; }
方法的逻辑非常清晰,我们可以很容易读懂类的连接过程,步骤总结如下:
- 连接父类和实现的接口。因为根据虚拟机规范,子类的初始化必然会导致父类的初始化,所以子类在连接之前自然要保证父类已经连接;
- 进行字节码验证;
- 重写类;
- 连接方法;
- 初始化vtable和itable;
- 将类的状态标记为已连接。
大概的执行逻辑如下图所示。
在连接类之前需要判断此类是否已经连接,之前介绍过,每个InstanceKlass中都定义了一个_init_state属性,如下:
u1 _init_state; // state of class
值只能为ClassState枚举类中定义的枚举常量,如下:
// See "The Java Virtual Machine Specification" section 2.16.2-5 for a detailed description // of the class loading & initialization procedure, and the use of the states. enum ClassState { allocated, // allocated (but not yet linked) loaded, // loaded and inserted in class hierarchy (but not linked yet) linked, // successfully linked/verified (but not initialized yet) 连接包括验证、准备和解析阶段 being_initialized, // currently running class initializer fully_initialized, // initialized (successfull final state) initialization_error // error happened during initialization };
这些状态主要标注一个类的加载、连接和初始化状态,3个过程已经在虚拟机规范中有了明确的规定,参考地址为https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html。
allocated状态表示已经分配内存,在InstanceKlass的构造函数中通常会将_init_state初始化为这个状态。
loaded状态表示类已经装载并且已经插入到继承体系中,在 SystemDictionary::add_to_hierarchy()方法中会更新InstanceKlass的_init_state状态。
linked状态表示已经成功连接/校验,只在InstanceKlass::link_class_impl()方法中更新为这个状态。
另外3个状态是在类的初始化方法InstanceKlass::initialize_impl()中会使用,后面也会介绍到。
相关文章的链接如下:
1、在Ubuntu 16.04上编译OpenJDK8的源代码
13、类加载器
14、类的双亲委派机制
15、核心类的预装载
16、Java主类的装载
17、触发类的装载
18、类文件介绍
19、文件流
20、解析Class文件
21、常量池解析(1)
22、常量池解析(2)
23、字段解析(1)
24、字段解析之伪共享(2)
25、字段解析(3)
28、方法解析
29、klassVtable与klassItable类的介绍
30、计算vtable的大小
31、计算itable的大小
32、解析Class文件之创建InstanceKlass对象
33、字段解析之字段注入
作者持续维护的个人博客 classloading.com。
关注公众号,有HotSpot源码剖析系列文章!
参考文章:
(1)Java对象分配原理