所以,一般来说(由字节码中是否跟随invokespecial指令所决定),执行new指令之后会接着执行init()方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算产生出来 。
对象的内存布局
在HotSpot虚拟机中 。对象在内存中存储的布局分为:
- 对象头
- 实例数据
- 对齐填充
HotSpot虚拟机的对象头包括两部分信息:运行时数据和类型指针 。
- 运行时数据:用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等 。
- 类型指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例 。

文章插图
如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小 。
(并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据并不一定要经过对象本身,可参考对象的访问定位)
HotSpot底层通过markOop实现Mark word,具体实现位于markOop.hpp文件 。markOop中提供了大量方法用于查看当前对象头的状态,以及更新对象头的数据,为synchronized锁的实现提供了基础 。[比如说我们知道synchronized锁的是对象而不是代码,而锁的状态保存在对象头中,进而实现锁住对象] 。有关synchronized的进一步介绍,可以点击查看:详解Java多线程锁之synchronized
实例数据
实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容 。无论是从父类中继承下来的,还是在子类中定义的,都需要记录下来 。HotSpot虚拟机默认的分配策略为longs/doubles、ints、shorts/chars、bytes/booleans、oop,从分配策略中可以看出,相同宽度的字段总是分配到一起 。
对齐填充
HotSpot虚拟机要求对象的起始地址必须是8字节的整数倍,也就是对象的大小必须是8字节的整数倍 。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐的时候,就需要通过对齐填充来补全 。
对象的访问定位
java程序需要通过引用(ref)数据来操作堆上面的对象,那么如何通过引用定位、访问到对象的具体位置 。
对象的访问方式由虚拟机决定,java虚拟机提供两种主流的方式
1.句柄访问对象
2.直接指针访问对象 。(Sun HotSpot使用这种方式)
句柄访问
简单来说就是java堆划出一块内存作为句柄池,引用中存储对象的句柄地址,句柄中包含对象实例数据、类型数据的地址信息 。
优点:引用中存储的是稳定的句柄地址,在对象被移动【垃圾收集时移动对象是常态】只需改变句柄中实例数据的指针,不需要改动引用【ref】本身 。

文章插图
直接指针
在这种方式中,JVM栈中的栈帧中的本地变量表中所存储的引用地址就是实例数据的地址 。通过这个引用就能直接获取到实例数据的地址 。
其实引用所指向的对内存中的对象数据有两部分组成,一部分就是这个对象实例本身,另一部分是对象类型在方法区中的地址 。优点:优势很明显,就是速度快,相比于句柄访问少了一次指针定位的开销时间 。由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本 。虚拟机Sun HotSpot而言,它是使用第二种方式进行对象访问的,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见 。

文章插图
推荐阅读
- 交换机接口的分类与连接
- Java必知必会:JVM是啥
- 服用五类药 最好别喝茶
- 淘宝小类目怎么运营 淘宝有什么冷门类目可以做
- 经典好看的校园重生文男主 有关于校园重生之类的小说
- 科学家|人类血液中首次发现微塑料 或已遍布全身:它们是如何进入人体的?
- 桌布的选购 桌布的分类
- 红茶的种类 红茶常见品种盘点
- 红茶有哪些 具体分类你造吗
- 红茶的种类 常见红茶的品种及鉴赏
