ClassFileParser::parseClassFile()方法会将解析Class文件的大部分结果保存到instanceKlass对象中。创建instanceKlass对象的代码如下:
int total_oop_map_size2 = InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count); // ReferenceType是枚举类,定义如下: /*enum ReferenceType { REF_NONE, // Regular class REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below REF_SOFT, // Subclass of java/lang/ref/SoftReference REF_WEAK, // Subclass of java/lang/ref/WeakReference REF_FINAL, // Subclass of java/lang/ref/FinalReference REF_PHANTOM // Subclass of java/lang/ref/PhantomReference }; */ // Compute reference type ReferenceType rt; // 与强引用、弱引用等有关 if (super_klass() == NULL) { rt = REF_NONE; } else { rt = super_klass->reference_type(); } // We can now create the basic Klass* for this klass InstanceKlass* skc = super_klass(); bool isnotnull = !host_klass.is_null(); _klass = InstanceKlass::allocate_instance_klass(loader_data, vtable_size, itable_size, info.static_field_size, // 注意 info.static_field_size 会被传进去,用于分配空间。 total_oop_map_size2, rt, access_flags, name, skc, isnotnull, CHECK_(nullHandle)); instanceKlassHandle this_klass(THREAD, _klass);
调用InstanceKlass::allocate_instance_klass()方法创建InstanceKlass对象,需要传入itable与vtable的大小,另外还需要传入static_field_size与OopMapBlock。这些都是在创建相关对象时计算内存占用大小所必须的参数。方法的实现如下:
InstanceKlass* InstanceKlass::allocate_instance_klass( ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, Symbol* name, Klass* super_klass, bool is_anonymous, TRAPS ){ bool isinterf = access_flags.is_interface(); int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, isinterf, is_anonymous); // Allocation InstanceKlass* ik; /////////////////////////////////////////////////////////////////////// if (rt == REF_NONE) { if (name == vmSymbols::java_lang_Class()) { ik = new (loader_data, size, THREAD) InstanceMirrorKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous); } else if ( name == vmSymbols::java_lang_ClassLoader() || ( SystemDictionary::ClassLoader_klass_loaded() && super_klass != NULL && // ClassLoader_klass为java_lang_ClassLoader super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass()) ) ){ ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous); } else { // normal class ik = new (loader_data, size, THREAD) InstanceKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous); } } /////////////////////////////////////////////////////////////////////// else { // reference klass ik = new (loader_data, size, THREAD) InstanceRefKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous); } /////////////////////////////////////////////////////////////////////// // 添加所有类型到我们内部类加载器列表中,包括在根加载器中的类 // Add all classes to our internal class loader list here, // including classes in the bootstrap (NULL) class loader. // loader_data的类型为ClassLoaderData*,通过ClassLoaderData中的_klasses保持通过InstanceKlass._next_link属性保持的列表 loader_data->add_class(ik); return ik; }
这个方法之前在介绍InstanceKlass对象时详细介绍过。
方法调用InstanceKlass::size()计算内存占用的大小,然后创建对应的C++对象来表示Java类型。
当rt等于REF_NONE时,也就是rt为非Reference类型时,会根据类名创建对应C++类的对象。Class类通过InstanceMirrorKlass对象表示、ClassLoader类或ClassLoader的子类通过InstanceClassLoaderKlass对象表示、普通类通过InstanceKlass对象表示。当rt不为REF_NONE时,也就是rt为Referece类型时,通过InstanceRefKlass对象来表示。这里只看InstanceKlass对象的创建过程,调用的构造函数如下:
InstanceKlass::InstanceKlass( int vtable_len, int itable_len, int static_field_size, // 注意这个静态变量大小的分配 int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous ) { No_Safepoint_Verifier no_safepoint; // until k becomes parsable bool tmp = access_flags.is_interface(); int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, tmp, is_anonymous); set_vtable_length(vtable_len); set_itable_length(itable_len); set_static_field_size(static_field_size); set_nonstatic_oop_map_size(nonstatic_oop_map_size); set_access_flags(access_flags); _misc_flags = 0; // initialize to zero set_is_anonymous(is_anonymous); assert(size() == iksize, "wrong size for object"); // ... set_init_state(InstanceKlass::allocated); // 注意在这里设置了类的状态为分配 // ... // initialize the non-header words to zero intptr_t* p = (intptr_t*)this; for (int index = InstanceKlass::header_size(); index < iksize; index++) { p[index] = NULL_WORD; } // Set temporary value until parseClassFile updates it with the real instance size. jint tti = Klass::instance_layout_helper(0, true); set_layout_helper(tti); }
可以看到在创建InstanceKlass时初始化了许多参数,也就是说解析Class文件的相关信息大多都会通过InstanceKlass等对象的属性保存起来,以支持虚拟机后续的运行。在构造函数中还需会将除header外的字初始化为NULL_WORD,将此类代表的Java类所创建出来的Java对象的大小初始化为0,后续会在parseClassFile()方法中更新这个值。
在创建instanceKlass实例时,通过向构造函数中传递一些参数来初始化相关参数,另外还会调用相关set方法来设置参数,重要的参数如下:
jint lh = Klass::instance_layout_helper(info.instance_size, false); this_klass->set_layout_helper(lh); // Not yet(还没有,还没): supers are done below to support the new subtype-checking fields this_klass->set_class_loader_data(loader_data); this_klass->set_nonstatic_field_size(info.nonstatic_field_size); this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields); this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]); // 有对_local_interfaces与_transitive_interfaces等属性的设置逻辑 apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL); if (has_final_method) { this_klass->set_has_final_method(); } this_klass->copy_method_ordering(method_ordering, CHECK_NULL); // The InstanceKlass::_methods_jmethod_ids cache // is managed on the assumption that the initial cache // size is equal to the number of methods in the class. If // that changes, then InstanceKlass::idnum_can_increment() // has to be changed accordingly. this_klass->set_initial_method_idnum(methods->length()); this_klass->set_name(cp->klass_name_at(this_class_index)); if (is_anonymous()){ // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve } this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); // Set up Method*::intrinsic_id as soon as(一...就...) we know the names of methods. // (We used to do this lazily, but now we query it in Rewriter, // which is eagerly done for every method, so we might as well(也;同样) do it now, // when everything is fresh in memory.) if (Method::klass_id_for_intrinsics(this_klass()) != vmSymbols::NO_SID) { for (int j = 0; j < methods->length(); j++) { Method* md = methods->at(j); md->init_intrinsic_id(); } } // ... // Miranda methods if ( (num_miranda_methods > 0) || // if this class introduced new miranda methods or ( super_klass.not_null() && (super_klass->has_miranda_methods()) ) // super class exists and this class inherited miranda methods ){ this_klass->set_has_miranda_methods(); // then set a flag } // Fill in information needed to compute superclasses. Klass* sk = super_klass(); this_klass->initialize_supers(sk, CHECK_(nullHandle)); // Initialize itable offset tables klassItable::setup_itable_offset_table(this_klass); // Compute transitive closure(闭包) of interfaces this class implements // Do final class setup fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts); // Fill in has_finalizer/has_vanilla_constructor/layout_helper set_precomputed_flags(this_klass); // Allocate mirror and initialize static fields java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle));
这里我们看到了许多之前介绍过的点,比如initialize_supers()方法、klassItable::setup_itable_offset_table()方法、fill_oop_maps()方法等。另外也更新了_layout_helper中的值,将此类代表的Java类所创建的Java实例的大小更新为info.instance_size,这个值是在之前计算字段布局时计算出来的,这里不再介绍。
调用的create_mirror()方法的实现如下:
oop java_lang_Class::create_mirror(KlassHandle k, Handle protection_domain, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); // ... // Class_klass has to be loaded because it is used to allocate the mirror. //////////////////////////////////////////////////////////////////////////////// if (SystemDictionary::Class_klass_loaded()) { // 注意 allocate_instance 内部会根据 k 中的信息,计算需要分配的空间,包含静态变量的大小。然后对 mirror 的空间进行分配。 // Allocate mirror (java.lang.Class instance) InstanceMirrorKlass* imk = InstanceMirrorKlass::cast(SystemDictionary::Class_klass()); Handle mirror = imk->allocate_instance(k, CHECK_0); // 返回的是instanceOop对象 // mirror是instanceOop对象,而mirror->klass()就是InstanceMirrorKlass*类型 InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); // mk代表的是java.lang.Class类 oop moop = mirror(); // moop代表的是java.lang.Class对象 int sofc = mk->compute_static_oop_field_count(moop); java_lang_Class::set_static_oop_field_count(moop, sofc); // It might also have a component mirror. This mirror must already exist. if (k->oop_is_array()) { // 数组 Handle comp_mirror; if (k->oop_is_typeArray()) { // 基本类型数组 BasicType type = TypeArrayKlass::cast(k())->element_type(); comp_mirror = Universe::java_mirror(type); // oop转换为Handle类型,会调用转换构造函数 } else { // 对象类型数组 assert(k->oop_is_objArray(), "Must be"); Klass* element_klass = ObjArrayKlass::cast(k())->element_klass(); assert(element_klass != NULL, "Must have an element klass"); comp_mirror = element_klass->java_mirror(); // oop转换为Handle类型,会调用转换构造函数 } assert(comp_mirror.not_null(), "must have a mirror"); // Two-way link between the array klass and its component mirror: oop tmp = comp_mirror(); ArrayKlass::cast(k())->set_component_mirror(tmp); set_array_klass(tmp, k()); } else { assert(k->oop_is_instance(), "Must be"); // ... // do_local_static_fields 会对静态字段进行初始化。 注意此是传入的函数指针表示的 initialize_static_field 函数, // do_local_static_fields 会在内部遍历所有静态字段,然后调用这个函数对他们进行初始化。 // Initialize static fields InstanceKlass* ik = InstanceKlass::cast(k()); ik->do_local_static_fields(&initialize_static_field, CHECK_NULL); } return mirror(); } //////////////////////////////////////////////////////////////////////////////// else { if (fixup_mirror_list() == NULL) { GrowableArray<Klass*>* list = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(40, true); set_fixup_mirror_list(list); } GrowableArray<Klass*>* list = fixup_mirror_list(); Klass* kls = k(); list->push(kls); return NULL; } //////////////////////////////////////////////////////////////////////////////// }
由于任何一个Java类都有一个Class对象来表示,所以在创建了表示普通Java类的InstanceKlass对象后,还需要创建对应的InstanceOop对象(代表Class对象)。如果java.lang.Class类还没有被解析,则将相关信息暂时存储到数组中,后续在类解析后会做处理,处理逻辑和当前类处理java.lang.Class类被加载时的逻辑基本一致。
调用的InstanceMirrorKlass::allocate_instance()方法创建的表示java中java.lang.Class对象的instanceOop实例。实现如下:
instanceOop InstanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) { // Query before forming handle. int size = instance_size(k); KlassHandle h_k(THREAD, this); instanceOop i = (instanceOop) CollectedHeap::Class_obj_allocate(h_k, size, k, CHECK_NULL); return i; } oop CollectedHeap::Class_obj_allocate(KlassHandle klass, int size, KlassHandle real_klass, TRAPS) { HeapWord* obj; obj = common_mem_allocate_init(real_klass, size, CHECK_NULL); // 分配内存并初始化为0 assert(Universe::is_bootstrapping() || !((oop)obj)->is_array(), "must not be an array"); oop mirror = (oop)obj; java_lang_Class::set_oop_size(mirror, size); // Setup indirections if (!real_klass.is_null()) { java_lang_Class::set_klass(mirror, real_klass()); real_klass->set_java_mirror(mirror); } return mirror; }
创建出表示了java.lang.Class对象的oop实例后,设置到InstanceKlass实例的_java_mirror属性中,同时也设置oop的_klass属性。如果当前类表示数组,那么在java_lang_Class::create_mirror()方法中还会设置表示数组的ArrayKlass对象的_component_mirror属性,同时也会设置表示当前数组的Class对象的_array_klass属性。
如果当前类是普通类,那么调用do_local_static_fields()方法,这个方法的实现如下:
void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAPS) { instanceKlassHandle h_this(THREAD, this); do_local_static_fields_impl(h_this, f, CHECK); } void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) { instanceKlassHandle ikh = this_oop(); for (JavaFieldStream fs(ikh); !fs.done(); fs.next()) { if (fs.access_flags().is_static()) { // 只处理静态字段,因为只有静态字段的值存储到Class对象中 fieldDescriptor& fd = fs.field_descriptor(); f(&fd, CHECK); } } }
调用的initialize_static_field()函数如下:
static void initialize_static_field(fieldDescriptor* fd, TRAPS) { InstanceKlass* fh = fd->field_holder(); oop tmp = fh->java_mirror(); Handle mirror( THREAD,tmp ); assert(mirror.not_null() && fd->is_static(), "just checking"); if (fd->has_initial_value()) { BasicType t = fd->field_type(); switch (t) { case T_BYTE: mirror()->byte_field_put(fd->offset(), fd->int_initial_value()); break; case T_BOOLEAN: mirror()->bool_field_put(fd->offset(), fd->int_initial_value()); break; case T_CHAR: mirror()->char_field_put(fd->offset(), fd->int_initial_value()); break; case T_SHORT: mirror()->short_field_put(fd->offset(), fd->int_initial_value()); break; case T_INT: mirror()->int_field_put(fd->offset(), fd->int_initial_value()); break; case T_FLOAT: mirror()->float_field_put(fd->offset(), fd->float_initial_value()); break; case T_DOUBLE: mirror()->double_field_put(fd->offset(), fd->double_initial_value()); break; case T_LONG:{ jlong offset = fd->offset(); jlong vo = fd->long_initial_value(); oop mr = mirror(); mr->long_field_put(offset,vo); break; } case T_OBJECT: { oop string = fd->string_initial_value(CHECK); mirror()->obj_field_put(fd->offset(), string); } break; default: THROW_MSG(vmSymbols::java_lang_ClassFormatError(),"Illegal ConstantValue attribute in class file"); }// end switch } }
do_local_static_fields()函数会对静态字段进行初始化,注意此时传入的函数指针指向initialize_static_field()函数,do_local_static_fields()会在内部遍历所有静态字段,然后调用这个函数对他们进行初始化。
相关文章的链接如下:
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的大小
作者持续维护的个人博客 classloading.com。
关注公众号,有HotSpot源码剖析系列文章!