1. 对象的创建过程
java 虚拟机遇到一条字节码new指令时,开始对象创建。
- 第一步:首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用。
若常量池中没有这个符号引用,那么表示这个类还没有被创建,抛出ClassNotFoundExecption异常。
检查这个符号引用代表的类是否已被加载、解析和初始化过。
若无,则先执行相应的类加载过程。 - 第二步:虚拟机将为新生对象分配内存。
对象所需内存的大小在类加载完成后便可完全确定。 - 第三步:内存分配完成后,虚拟机将分配到的内存空间(不包括对象头)都初始化为零值。
保证对象的实例字段在JAVA代码中可以不赋初始值就能直接使用,使程序能够访问都这些字段的数据类型所对应的零值。 - 第四步:对对象进行必要的设置(在对象头中设置相关信息)
上面的四个步骤完成后,从jvm角度看,一个新对象已经产生了。从java 程序看,才刚开始,构造函数还没有执行(对应class文件<init>方法)
- 第五步:调用构造函数完成初始化。
new 指令之后会接着执行<init>方法。执行完之后,一个对象完全构造出来了!
2. 对象在内存中的存储布局
在64位操作系统下,以 Object o = new Object()为例

-
class pointer(类型指针)
对象指向它的类型元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
存放类型指针的空间大小占8个字节,开启指针压缩的情况下,占4个字节
-
length(数组长度)
数组对象专有,用来存放数组的长度。占4个字节。 -
实例数据
实例数据部分是对象真正存储的有效信息,即程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。
HotSpot 默认的分配顺序是:long/double int short/char byte/boolean oops(ordinary object pointers,OOPS).
相同宽度的字段总是被分配到一起存放。 -
padding(对齐)
当整个内存的字节数要是8字节的整数倍,如果不是补上相应的字节数到padding中。 -
mark word(标记字段)
存储锁的相关信息等,占8个字节
mark word (1).jpg
3. 对象的访问定位
通过栈上的reference 数据来操作堆上具体的对象
对象的访问方式有虚拟机各自实现,主流的访问方式有两种。
- 使用句柄
java 堆中将划分出一块内存作为句柄池。reference 中存储的是对象的句柄地址。句柄中包含了对象实例数据与类型数据各自具体的地址信息。 - 直接指针
reference存储的是对象地址。
网友评论