环境
本系列学习笔记基于openjdk-8u60版本
OOP-Klass二分模型
Hotspot基于C++实现,而C++本身也是一门面向对象的语言,那么是否只需要对每个Java类生成一个对应的C++类,当Java创建实例对象时,C++也创建一个实例对象?事实上, HotSpot并没有这么做,而是设计了一套OOP-Klass二分模型:
OOP: ordinary object pointer, 即普通对象指针,用来描述对象实例信息;
Klass:Java类的C++对等体,用来描述Java类信息。
这么设计的主要目的在于OOP对象表示对象的实例信息即可,不想持有虚函数。而描述Java类的Klass对象中有VTBL信息,可以根据Java对象的实际类型进行分发,这样就避免了在每个实例对象中都分配VTBL指针。
详细信息可参考《HotSpot实战》第二章
HopSpot加载和解析Class文件
我们知道,java加载class最终会调用native方法defineClass1,底层实现入口ClassLoader.c中的Java_java_lang_ClassLoader_defineClass1->jvm.cpp中的jvm_define_class_common方法,其中核心加载方法为SystemDictionary.cpp中的resolve_from_stream方法:
//从流中加载klass到系统字典中,其中流为jni_DefineClass、JVM_DefineClass
Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
bool verify,
TRAPS) {
// Classloader是否支持并行加载(jdk1.7后支持并行加载,并行加载即classLoader可同时加载多个class,而在1.7之前classLoader方法是同步的),不支持则加锁
bool DoObjectLock = true;
if (is_parallelCapable(class_loader)) {
DoObjectLock = false;
}
ClassLoaderData* loader_data = register_loader(class_loader, CHECK_NULL);
// 确保对class加锁
Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
check_loader_lock_contention(lockObject, THREAD);
ObjectLocker ol(lockObject, THREAD, DoObjectLock);
TempNewSymbol parsed_name = NULL;
// 解析class文件流
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
loader_data,
protection_domain,
parsed_name,
verify,
THREAD);
const char* pkg = "java/";
if (!HAS_PENDING_EXCEPTION &&
!class_loader.is_null() &&
parsed_name != NULL &&
!strncmp((const char*)parsed_name->bytes(), pkg, strlen(pkg))) {
// It is illegal to define classes in the "java." package from
// JVM_DefineClass or jni_DefineClass unless you're the bootclassloader
// 除了bootclassloader,其他加载器不能加载java.路径的包,略
if (!HAS_PENDING_EXCEPTION) {
//略
// Add class just loaded
// If a class loader supports parallel classloading handle parallel define requests
// find_or_define_instance_class may return a different InstanceKlass
if (is_parallelCapable(class_loader)) {
k = find_or_define_instance_class(class_name, class_loader, k, THREAD);
} else {
define_instance_class(k, THREAD);
}
}
return k();
}
解析class流方法parseClassFile就不看了,和《深入理解Java虚拟机》中说的一样:
- 验证魔数;
- 验证minor_version、major_version,并验证jvm是否支持版本
- 解析常量池(后面在分析)
- access_flags判断;
- 父类、接口解析等元数据验证
- 字节码、符号验证等。。
解析完成后,会创建InstanceKlass:
// We can now create the basic Klass* for this klass
_klass = InstanceKlass::allocate_instance_klass(loader_data,
vtable_size,
itable_size,
info.static_field_size,
total_oop_map_size2,
rt,
access_flags,
name,
super_klass(),
!host_klass.is_null(),
CHECK_(nullHandle)){
//计算InstanceKlass的size,在编译期可确定
int size = InstanceKlass::c(vtable_len, itable_len, nonstatic_oop_map_size,
access_flags.is_interface(), 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 &&
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
//普通类会走这个分支,生成一个InstanceKlass实例
//操作符重载,会调用Klass::operator new
ik = new (loader_data, size, THREAD) InstanceKlass(
vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
access_flags, is_anonymous);
}
} else {op
// 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);
}
// Check for pending exception before adding to the loader data and incrementing
// class count. Can get OOM here.
if (HAS_PENDING_EXCEPTION) {
return NULL;
}
// Add all classes to our internal class loader list here,
// including classes in the bootstrap (NULL) class loader.
// 将instanceKlass放入class loader中
loader_data->add_class(ik);
Atomic::inc(&_total_instanceKlass_count);
return ik;
}
allocate_instance_klass方法主要是生成一个InstanceKlass,并设置一些信息。这里要注意下InstanceKlass内存的分配。我们知道jdk8后,元数据信息是分配到metaspace(本地内存)中的,这里使用了操作符重载,调用Klass::operator new,这里就会调用Metaspace分配内存:
void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw() {
return Metaspace::allocate(loader_data, word_size, /*read_only*/false,
MetaspaceObj::ClassType, CHECK_NULL);
}
InstanceKlass布局如下:
// InstanceKlass layout:
// [C++ vtbl pointer ] Klass
// [subtype cache ] Klass
// [instance size ] Klass
// [java mirror ] Klass
// [super ] Klass
// [access_flags ] Klass
// [name ] Klass
// [first subklass ] Klass
// [next sibling ] Klass
// [array klasses ]
// [methods ]
// [local interfaces ]
// [transitive interfaces ]
// [fields ]
// [constants ]
// [class loader ]
// [source file name ]
// [inner classes ]
// [static field size ]
// [nonstatic field size ]
// [static oop fields size ]
// [nonstatic oop maps size ]
// [has finalize method ]
// [deoptimization mark bit ]
// [initialization state ]
// [initializing thread ]
// [Java vtable length ]
// [oop map cache (stack maps) ]
// [EMBEDDED Java vtable ] size in words = vtable_len
// [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size
// The embedded nonstatic oop-map blocks are short pairs (offset, length)
// indicating where oops are located in instances of this klass.
// [EMBEDDED implementor of the interface] only exist for interface
// [EMBEDDED host klass ] only exist for an anonymous class (JSR 292 enabled)
生成instanceClass,会继续填充信息(以下只是列举部分填充代码):
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]);
填充完成后,会生成InstanceKlass对应在Java层面的class对象:
// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(this_klass, class_loader, protection_domain,
CHECK_(nullHandle));
最后再回到resolve_from_stream方法,当解析完class后,class_loader会将instanceKlass放入自身的SystemDictionary中,即find_or_define_instance_class方法。find_or_define_instance_class方法主要做几件事:
- class_loader从SystemDictionary查询该class是否已加载过,若无则将instanceKlass注册到SystemDictionary中(加锁),否则将instanceKlass加到移除队列,返回已有的instanceKlass;
- 加载完成后,通知一些等待加载的线程等操作。