仅限于普通Java对象,不包括数组和Class对象;不包括复制(克隆?)、反序列化。
HotSpot虚拟机字节码解释器中的代码片段
// 确保常量池中存放的是已解释的类 if (!constants->tag_at(index).is_unresolved_klass()) { // 断言确保是klassOop和instanceKlassOop(这部分下一节介绍) oop entry = (klassOop) *constants->obj_at_addr(index); assert(entry->is_klass(), "Should be resolved klass"); klassOop k_entry = (klassOop) entry; assert(k_entry->klass_part()->oop_is_instance(), "Should be instanceKlass"); instanceKlass* ik = (instanceKlass*) k_entry->klass_part(); // 确保对象所属类型已经经过初始化阶段 if ( ik->is_initialized() && ik->can_be_fastpath_allocated() ) { // 取对象长度 size_t obj_size = ik->size_helper(); oop result = NULL; // 记录是否需要将对象所有字段置零值 bool need_zero = !ZeroTLAB; // 是否在TLAB中分配对象 if (UseTLAB) { result = (oop) THREAD->tlab().allocate(obj_size); } if (result == NULL) { need_zero = true; // 直接在eden中分配对象 retry: HeapWord* compare_to = *Universe::heap()->top_addr(); HeapWord* new_top = compare_to + obj_size; // cmpxchg是x86中的CAS指令,这里是一个C++方法,通过CAS方式分配空间,并发失败的 话,转到retry中重试直至成功分配为止 if (new_top <= *Universe::heap()->end_addr()) { \ if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) { goto retry; } result = (oop) compare_to; } } if (result != NULL) { // 如果需要,为对象初始化零值 if (need_zero ) { HeapWord* to_zero = (HeapWord*) result + sizeof(oopDesc) / oopSize; obj_size -= sizeof(oopDesc) / oopSize; if (obj_size > 0 ) { memset(to_zero, 0, obj_size * HeapWordSize); } } // 根据是否启用偏向锁,设置对象头信息 if (UseBiasedLocking) { result->set_mark(ik->prototype_header()); } else { result->set_mark(markOopDesc::prototype()); } result->set_klass_gap(0); result->set_klass(k_entry); \ // 将对象引用入栈,继续执行下一条指令 SET_STACK_OBJECT(result, 0); UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1); } } }
HotSpot中,对象在堆内存中的布局可分为三个部分:对象头、实例数据、对齐填充。
对象头
实例数据
对齐填充
Java程序通过栈上的reference操作堆上的具体对象。《JVM规范》仅规定了reference是一个指向对象的引用,并未规定这个引用该通过什么方式去定位、访问到堆中对象的具体位置。
主流访问方式主要有使用句柄和直接指针两种。
句柄
Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息
直接指针
Java堆中对象的内存布局就必须考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问的开销
直接指针:速度更快,它节省了一次指针定位的时间开销,HotSpot使用它