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的源代码

2、调试HotSpot源代码

3、HotSpot项目结构 

4、HotSpot的启动过程

5、HotSpot二分模型(1)

6、HotSpot的类模型(2)

7、HotSpot的类模型(3)

8、HotSpot的类模型(4)

9、HotSpot的对象模型(5)

10、HotSpot的对象模型(6)

11、操作句柄Handle(7)

12、句柄Handle的释放(8)

13、类加载器

14、类的双亲委派机制

15、核心类的预装载

16、Java主类的装载

17、触发类的装载

18、类文件介绍

19、文件流

20、解析Class文件

21、常量池解析(1)

22、常量池解析(2)

23、字段解析(1)

24、字段解析之伪共享(2)

25、字段解析(3)

26、字段解析之OopMapBlock(4)

27、方法解析之Method与ConstMethod介绍

28、方法解析

29、klassVtable与klassItable类的介绍

30、计算vtable的大小

31、计算itable的大小

作者持续维护的个人博客  classloading.com

关注公众号,有HotSpot源码剖析系列文章!

 

 

  

解析Class文件之创建InstanceKlass对象的更多相关文章

  1. sax解析xml文件,封装到对象中

    创建User.java类 public class User { private String id; private String name; private String age; private ...

  2. Java&Xml教程(五)使用SAX方式解析XML文件

    Java SAX解析机制为我们提供了一系列的API来处理XML文件,SAX解析和DOM解析方式不太一样,它并不是將XML文件内容一次性全部加载,而是连续的部分加载. javax.xml.parsers ...

  3. XML专题:使用NSXMLParser解析xml文件

    使用NSXMLParser解析xml文件 1. 设置委托对象,开始解析     NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data ...

  4. 遍历文件 创建XML对象 方法 python解析XML文件 提取坐标计存入文件

    XML文件??? xml即可扩展标记语言,它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言. 里面的标签都是可以随心所欲的按照他的命名规则来定义的,文件名为roi.xm ...

  5. Android -- 创建XML文件对象及其序列化, pull解析XML文件

    1. 创建XML文件对象及其序列化 示例代码:(模拟以xml格式备份短信到SD卡) SmsInfo.java, bean对象 /** * 短信的业务bean * @author Administrat ...

  6. 使用dom4j创建和解析xml文件

    使用dom4j创建和解析xml文件 在项目开发中,我们经常会遇到xml文件的创建和解析从别人接口得到的xml文件,而我们最常使用的组件是dom4j. 下面我就以代码来讲解一下如何使用dom4j来创建x ...

  7. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

  8. 创建xml文件、解析xml文件

        1.创建XML文件: import codecs import xml.dom.minidom doc=xml.dom.minidom.Document() print doc root=do ...

  9. 使用XPath对象解析xml文件

    使用XPath对象解析xml文件 1.DocumentBuilderFactory类  工厂API,使应用程序能从XML文档获取生成DOM对象树的解析器 其构造方法受保护,用newInstance() ...

随机推荐

  1. p44_IP数据包格式

    一.IP数据报格式 二.IP分片 数据链路层每帧可封装数据有上限,IP数据超过的要分片. 标识:同一数据报的分片使用同一标识 标志: 片偏移(13bit):用于还原数据报顺序,指出某片在原分组1中的相 ...

  2. 设计模式:prototype模式

    使用场景:在不能根据类创建对象的时候,根据已有的对象创建对象 不能根据类创建对象的情况: 创建一个类的对象时,需要根据多种对象来创建,创建的过程非常复杂 难以根据类生成对象 例子: class Pro ...

  3. 17 个 Python 特别实用的操作技巧,记得收藏!

    Python 是一门非常优美的语言,其简洁易用令人不得不感概人生苦短.在本文中,作者 Gautham Santhosh 带我们回顾了 17 个非常有用的 Python 技巧,例如查找.分割和合并列表等 ...

  4. 将数组内的元素循环左移P个位置

    问题可以转化为将数组内前 n 个元素进行逆置,再将后(n-p)个元素逆置,最后将整个数组逆置 void Reverse(int A[],int pos1,int pos2){ // 将A[pos1]与 ...

  5. Android Studio报错问题集锦

    Android Studio使用过程中坑太多,动不动就报错,每次出现问题都是上百度去搜索,需要花费很大的时间和精力才能解决掉问题. 为了以后更高效的使用这款工具,在这里记录下来我已经踩过的坑和即将要踩 ...

  6. GhostNet: More Features from Cheap Operations

    论文:GhostNet: More Features from Cheap Operations,CVPR 2020 代码:https://github.com/iamhankai/ghostnet. ...

  7. VMware虚拟机黑屏解决

    1.管理员身份运行cmd(右键->以管理员身份运行) 2.修复LSP,输入以下命令然后回车 netsh winsock reset 3.重启电脑即可

  8. Android集成JPush(极光推送)

    目前只是简单的集成 1.在极光推送官网注册用户 2.创建应用 3.配置包名,获得APPKEY 去设置 输入应用包名 确定然后返回查看APPKEY 3.在应用中集成极光推送 用的jcenter自动集成的 ...

  9. NanoHTTPD服务

    需要导入nanohttpd2.3,jar包 继承NanoHTTPD public class HttpServer extends NanoHTTPD { public HttpServer(int ...

  10. Kafka和SpringBoot

    事先必备: kafka已安装完成 1.目录结构 2.父pom <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns ...