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源碼剖析系列文章!