本文让我们继续梳理类加载的流程,分析的代码为:
_klassKlassObj = klassKlass::create_klass(CHECK);
这里先说明2个问题:
-
为啥要首先创建klassKlass?
因为klassKlass 是klass链路的末端.不可能oop-klass 一直这么的指下去,必须有个终点.这个终点就是klassKlass.
-
CHECK 是啥?
CHECK 是宏,定义如下:
#define CHECK THREAD); if (HAS_PENDING_EXCEPTION) return ; (0 #define THREAD __the_thread__ #define HAS_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->has_pending_exception()) #define TRAPS Thread* THREAD
那么因此宏展开后就是:
_klassKlassObj = klassKlass::create_klass(__the_thread__); if((((ThreadShadow*) __the_thread__)->has_pending_exception())) return ; (0);
那么这里的 _the_thread_ 是哪来的呢?
由于该方法是void Universe::genesis(TRAPS),宏展开后正好是:
void Universe::genesis(Thread* __the_thread__)
因此,该_the_thread_ 是由Universe::genesis方法的参数而来.
解析
klassKlass::create_klass方法实现如下:
klassOop klassKlass::create_klass(TRAPS) {
KlassHandle h_this_klass;
klassKlass o;
// for bootstrapping, handles may not be available yet.
klassOop k = base_create_klass_oop(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL);
k->set_klass(k); // point to thyself 自指
// Do not try to allocate mirror, java.lang.Class not loaded at this point.
// See Universe::fixup_mirrors()
return k;
}
这里有4行代码,很明显就做了4件事:
- 创建 KlassHandle
- 创建 klassKlass
- 创建 klassOop
- 自指
创建 KlassHandle
这里先贴一下KlassHandle的类图:
由于创建 KlassHandle 所对应的代码为:
KlassHandle h_this_klass;
因此会执行如下代码:
KlassHandle () : Handle() {}
此时会执行Handle()的构造器:
Handle() { _handle = NULL; }
此时的状态如图所示:
创建 klassKlass
这里先贴下klassKlass的类图:
由于创建 klassKlass 所对应的代码为:
klassKlass o;
同时,由于没有定义构造器,因此这里也就没什么好说的了…
创建 klassOop
此处执行的代码为:
klassOop k = base_create_klass_oop(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL);
这里首先调用了header_size()方法,如下:
static int header_size() { return oopDesc::header_size() + sizeof(klassKlass)/HeapWordSize; }
而 oopDesc::header_size() 实现如下:
static int header_size() { return sizeof(oopDesc)/HeapWordSize; }
由于oopDesc 定义了如下字段:
volatile markOop _mark;
union _metadata {
wideKlassOop _klass;
narrowOop _compressed_klass;
} _metadata;
那么在64位上,sizeof(oopDesc) 会返回如下结果:
- 如果未开启指针压缩,返回 16
- 如果开启指针压缩,返回 12
在 32位上,sizeof(oopDesc) 会返回如下结果: 8
因此,oopDesc::header_size() 会返回 2
同时,由于 sizeof(klassKlass)/HeapWordSize = 108/4 = 27 (32 位情况下)
因此,klassklass::header_size() 最终返回的是 29 .
另外, o.vtbl_value() 代码如下:
const Klass_vtbl& vtbl_value() const { return *this; }
回到Klass::base_create_klass_oop方法中,代码如下:
klassOop Klass::base_create_klass_oop(KlassHandle& klass, int size,
const Klass_vtbl& vtbl, TRAPS) {
size = align_object_size(size);
// allocate and initialize vtable
Klass* kl = (Klass*) vtbl.allocate_permanent(klass, size, CHECK_NULL);
klassOop k = kl->as_klassOop();
{ // Preinitialize supertype information.
// A later call to initialize_supers() may update these settings:
kl->set_super(NULL);
for (juint i = 0; i < Klass::primary_super_limit(); i++) {
kl->_primary_supers[i] = NULL;
}
kl->set_secondary_supers(NULL);
oop_store_without_check((oop*) &kl->_primary_supers[0], k);
kl->set_super_check_offset(primary_supers_offset_in_bytes() + sizeof(oopDesc));
}
// 初始化Klass
kl->set_java_mirror(NULL);
kl->set_modifier_flags(0);
kl->set_layout_helper(Klass::_lh_neutral_value);
kl->set_name(NULL);
AccessFlags af;
af.set_flags(0);
kl->set_access_flags(af);
kl->set_subklass(NULL);
kl->set_next_sibling(NULL);
kl->set_alloc_count(0);
kl->set_alloc_size(0);
// JVM内部虽然将klass也封装成立oop,但是klass毕竟也是独立的一种类型,因此也需要记录线程锁等相关标识
kl->set_prototype_header(markOopDesc::prototype());
kl->set_biased_lock_revocation_count(0);
kl->set_last_biased_lock_bulk_revocation_time(0);
return k;
}
可以分为3部分:
-
内存对齐
-
将Klass分配在永久区
-
初始化klassOop的数据
内存对齐
此处内存对齐实现如下:
inline intptr_t align_object_size(intptr_t size) {
return align_size_up(size, MinObjAlignment);
}
inline intptr_t align_size_up(intptr_t size, intptr_t alignment) {
return align_size_up_(size, alignment);
}
#define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))
MinObjAlignment = 2
Klass分配在永久区
此处代码实现如下:
void* allocate_permanent(KlassHandle& klass_klass, int size, TRAPS) const { \
void* result = new(klass_klass, size, THREAD) thisKlass(); \
if (HAS_PENDING_EXCEPTION) return NULL; \
klassOop new_klass = ((Klass*) result)->as_klassOop(); \
OrderAccess::storestore(); \
post_new_init_klass(klass_klass, new_klass, size); \
return result; \
}
注意,由于Klass_vtbl中重载了new操作符,如下:
void* operator new(size_t ignored, KlassHandle& klass, int size, TRAPS);
因此,此处最终执行的代码如下所示:
void* Klass_vtbl::operator new(size_t ignored, KlassHandle& klass,
int size, TRAPS) {
// The vtable pointer is installed during the execution of
// constructors in the call to permanent_obj_allocate(). Delay
// the installation of the klass pointer into the new klass "k"
// until after the vtable pointer has been installed (i.e., until
// after the return of permanent_obj_allocate().
klassOop k =
(klassOop) CollectedHeap::permanent_obj_allocate_no_klass_install(klass,
size, CHECK_NULL);
return k->klass_part();
}
这里调用了CollectedHeap::permanent_obj_allocate_no_klass_install方法,代码如下:
oop CollectedHeap::permanent_obj_allocate_no_klass_install(KlassHandle klass,
int size,
TRAPS) {
HeapWord* obj = common_permanent_mem_allocate_init(size, CHECK_NULL); // 为oop 申请内存
post_allocation_setup_no_klass_install(klass, obj, size); // 初始化klassOop._mark标识
return (oop)obj;
}
这里做了2件事:
- 为oop 申请内存
- 初始化klassOop._mark标识
先来看oop 申请内存的部分:
HeapWord* CollectedHeap::common_permanent_mem_allocate_init(size_t size, TRAPS) {
HeapWord* obj = common_permanent_mem_allocate_noinit(size, CHECK_NULL); // 1. 为klassOop申请内存
init_obj(obj, size); // 2. klassOop内存清零
return obj;
}
2件事:
- 为klassOop申请内存
- klassOop内存清零
其中,申请内存最终执行的代码是:
HeapWord* result = Universe::heap()->permanent_mem_allocate(size);
if (result != NULL) {
return result;
}
这里,gc使用的是parallelScavenge,其最终分配内存代码如下:
result = perm_gen()->allocate_permanent(size);
if (result != NULL) {
return result;
}
------------ psPermGen.cpp --------
HeapWord* PSPermGen::allocate_permanent(size_t size) {
assert_locked_or_safepoint(Heap_lock);
// 直接进行分配
HeapWord* obj = allocate_noexpand(size, false);
if (obj == NULL) {
// 如果分配失败,则扩容后,在进行分配
obj = expand_and_allocate(size, false);
}
return obj;
}
-------------psOldGen.hpp -----
HeapWord* allocate_noexpand(size_t word_size, bool is_tlab) {
// We assume the heap lock is held here.
assert(!is_tlab, "Does not support TLAB allocation");
assert_locked_or_safepoint(Heap_lock);
HeapWord* res = object_space()->allocate(word_size);
if (res != NULL) {
_start_array.allocate_block(res);
}
return res;
}
这里最终会执行 MutableSpace::allocate 方法,如下:
HeapWord* MutableSpace::allocate(size_t size) {
assert(Heap_lock->owned_by_self() ||
(SafepointSynchronize::is_at_safepoint() &&
Thread::current()->is_VM_thread()),
"not locked");
/*
* 注意,这里先执行HeapWord* obj = top();再执行 HeapWord* new_top = obj + size;,而最终返回的是obj指针,该指针指向的是原来的堆的最顶端,
* 这样,调用方通过指针可以还原从原顶端到当前堆顶之间的内存空间,将其强制转换为常量池对象.
*/
HeapWord* obj = top();
if (pointer_delta(end(), obj) >= size) {
HeapWord* new_top = obj + size; // 将PermSpace内存区域的top指针往高地址移动了size大小的字节数,完成了当前被加载的类所对应的常量池的内存分配
set_top(new_top);
assert(is_object_aligned((intptr_t)obj) && is_object_aligned((intptr_t)new_top),
"checking alignment");
return obj;
} else {
return NULL;
}
}
关键点都在注释中,这里就不在解释了…
接下来,我们来看一看内存清零部分:
void CollectedHeap::init_obj(HeapWord* obj, size_t size) {
assert(obj != NULL, "cannot initialize NULL object");
const size_t hs = oopDesc::header_size();
assert(size >= hs, "unexpected object size");
((oop)obj)->set_klass_gap(0);
Copy::fill_to_aligned_words(obj + hs, size - hs);
}
static void fill_to_aligned_words(HeapWord* to, size_t count, juint value = 0) {
assert_params_aligned(to);
pd_fill_to_aligned_words(to, count, value);
}
注意,这里的value 默认值是 0 .
--------copy_x86.hpp ----
static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
pd_fill_to_words(tohw, count, value);
}
static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) {
#ifdef AMD64
julong* to = (julong*) tohw;
julong v = ((julong) value << 32) | value;
while (count-- > 0) {
*to++ = v;
}
#else
juint* to = (juint*)tohw;
count *= HeapWordSize / BytesPerInt;
while (count-- > 0) {
*to++ = value;
}
#endif // AMD64
}
现在目光回到CollectedHeap::permanent_obj_allocate_no_klass_install方法中,当分配完内存后,接下来就会初始化klassOop._mark标识.如下:
void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass,
HeapWord* objPtr,
size_t size) {
oop obj = (oop)objPtr;
assert(obj != NULL, "NULL object pointer");
if (UseBiasedLocking && (klass() != NULL)) {
obj->set_mark(klass->prototype_header());
} else {
// May be bootstrapping
obj->set_mark(markOopDesc::prototype());
}
}
注意,此时由于klass() 为 NULL,因此,此处执行如下代码:
obj->set_mark(markOopDesc::prototype());
static markOop prototype() {
return markOop( no_hash_in_place | no_lock_in_place );
}
注意,此处用到了c++的技巧,由于markOop为指针类型,因此,此处的代码就相当于:
markOopDesc* mark = (markOopDesc*)(no_hash_in_place | no_lock_in_place);
return mark;
此时 klassKlass 状态如下:
此时目光回到allocate_permanent方法中,此处该执行如下代码:
klassOop new_klass = ((Klass*) result)->as_klassOop();
post_new_init_klass(klass_klass, new_klass, size);
我们来看,由于此处创建的是klassklass,其申请的内存空间为: oopDesc::header_size() + sizeof(klassKlass)/HeapWordSize
而在Klass::as_klassOop方法中,实现如下:
klassOop as_klassOop() const {
// see klassOop.hpp for layout.
return (klassOop) (((char*) this) - sizeof(klassOopDesc));
}
则此处new_klass 指向的是属于klassKlass 数据的部分:
然后我们再来看post_new_init_klass方法的实现:
void Klass_vtbl::post_new_init_klass(KlassHandle& klass,
klassOop new_klass,
int size) const {
assert(!new_klass->klass_part()->null_vtbl(), "Not a complete klass");
CollectedHeap::post_allocation_install_obj_klass(klass, new_klass, size);
}
void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass,
oop obj,
int size) {
obj->set_klass(klass());
}
inline void oopDesc::set_klass(klassOop k) {
// since klasses are promoted no store check is needed
assert(Universe::is_bootstrapping() || k != NULL, "must be a real klassOop");
assert(Universe::is_bootstrapping() || k->is_klass(), "not a klassOop");
if (UseCompressedOops) {
oop_store_without_check(compressed_klass_addr(), (oop)k);
} else {
oop_store_without_check(klass_addr(), (oop) k);
}
}
这里调用了klass_addr()方法,获得_metadata的地址,进行赋值.如下:
inline oop* oopDesc::klass_addr() {
// Only used internally and with CMS and will not work with
// UseCompressedOops
assert(!UseCompressedOops, "only supported with uncompressed oops");
return (oop*) &_metadata._klass;
}
由于此处的k是由klass()而来的,由于KlassHandle重载了()操作符,如下:
klassOop operator () () const { return obj(); }
klassOop obj() const { return (klassOop)Handle::obj(); }
---- Handle
oop obj() const { return _handle == NULL ? (oop)NULL : *_handle; }
注意,由于这里的KlassHandle是由之前透传的,因此这里最终会将_metadata 赋值为null.如图所示:
初始化klassOop的数据
这里需要介绍一点的是,JVM内部虽然将klass也封装成立oop,但是klass毕竟也是独立的一种类型,因此也需要记录线程锁等相关标识.如下:
kl->set_prototype_header(markOopDesc::prototype());
kl->set_biased_lock_revocation_count(0);
kl->set_last_biased_lock_bulk_revocation_time(0);
自指
此时回到了klassKlass::create_klass方法中,执行了如下代码:
k->set_klass(k); // point to thyself 自指
此时,klassKlass如图所示:
此时就完成了klassOop的创建.
总结
创建klassKlass的时序图如下,图中有些步骤省略了…