本文基于openjdk11及hotspot
Java对象模型: OOP-Klass模型
(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)
在正式探讨JVM对象的创建前,先简单地介绍一下hotspot中实现的Java的对象模型。在JVM中,并没有直接将Java对象映射成C++对象,而是采用了oop-klass模型,主要是不希望每个对象中都包含有一份虚函数表,其中:
- OOP(Ordinary Object Point),表示对象的实例信息
- Klass,是Java类的在C++中的表示,用来描述Java类的信息
简单地说,一个Java类在JVM中被拆分为了两个部分:数据和描述信息,分别对应OOP和Klass。
在具体的JVM源码中,当加载一个Class时,会创建一个InstanceKlass对象,实例化的对象则对应InstanceOopDesc,其中InstanceKlass存放在元空间,InstanceOopDesc存放在堆中。
对象创建过程
首先先来看InstanceOopDesc的数据结构,InstanceOopDesc继承了OopDesc,数据结构如下
// 此处为了方便阅读,改写了一下代码
class instanceOopDesc : public oopDesc {
private:
volatile markOop _mark;
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
};
其中_metadata指向该对象的InstanceKlass,而_mark中则存储了对象运行时的状态数据,数据结构如下(图中为32位的情况下的数据,64位也大同小异)
32 bits:
--------
hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
size:32 ------------------------------------------>| (CMS free block)
PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
每一行都代表了一种情况,描述了哈希码、GC分代年龄、锁等状态信息,如下:
hash: 哈希码
age: 分代年龄
biased_lock: 偏向锁标识位
lock: 锁状态标识位
JavaThread*: 持有偏向锁的线程ID
epoch: 偏向时间戳
instanceOopDesc其实保存的是对象的头部信息,除了头部信息,对象还有数据,对象数据紧跟着头部后面,图示如下:
1. 入口
上图截取了一段程序字节码,红线所框对应了Java中new操作的字节码,Java中的new操作对应了字节码的三个操作,本文主要讲述第一个操作(new)。字节码中new操作对应JVM中的InterpreterRuntime::_new,代码如下,
// hotspot/share/interpreter/interpreterRuntime.cpp
IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool, int index))
Klass* k = pool->klass_at(index, CHECK);
InstanceKlass* klass = InstanceKlass::cast(k);
klass->check_valid_for_instantiation(true, CHECK); // 校验:接口/抽象类/Class不能实例化
klass->initialize(CHECK); // 初始化klass
oop obj = klass->allocate_instance(CHECK); // 分配实例
thread->set_vm_result(obj);
IRT_END
里面主要包含了两个部分:初始化klass和分配实例
2. 初始化klass
// hotspot/share/oops/instanceKlass.cpp
void InstanceKlass::initialize(TRAPS) {
if (this->should_be_initialized()) {
initialize_impl(CHECK);
} else {
assert(is_initialized(), "sanity check");
}
}
在这里我们继续看initialize_impl()方法
// hotspot/share/oops/instanceKlass.cpp
void InstanceKlass::initialize_impl(TRAPS) {
HandleMark hm(THREAD);
link_class(CHECK); // 链接class
bool wait = false;
// Step 1
{
Handle h_init_lock(THREAD, init_lock());
ObjectLocker ol(h_init_lock, THREAD, h_init_lock() != NULL);
Thread *self = THREAD;
// Step 2
while(i