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