*将以前写的一篇博客重新整理
对象的创建(仅限普通对象,不包括数组和Class对象)分为五个步骤:
虚拟机遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,就必须进行相应的类加载过程。
类加载检查通过后,要进行分配内存。对象所需的内存大小在类加载完成后便可完全确定,为对象分配内存的任务便转化成把一块大小确定的内存从Java堆中划分出来。
有两种方式:“指针碰撞”和“空闲列表”:
这两种分配方式并没有绝对的好坏之分,有的虚拟机使用指针碰撞,有的虚拟机使用空闲列表。
除如何划分空间外,另一个问题是线程同步问题。因为即使移动一个指针,在并发情况下也可能是不安全的。解决这个问题同样有两种方案:
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)。如果使用TLAB,该工作可以提前至TLAB分配时进行。
虚拟机要对对象进行必要设置,例如这个对象是哪个类的实例,如何找到类的元数据信息、对象的哈希码、对象的GC分代年龄等。这些信息存放在对象头中。这个看下面的对象内存布局
一般来说,执行new指令后会接着执行<init>方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象就产生了。
对象在内存中的布局可以分为3块区域:对象头、实例数据和对齐填充。
对象头包括两部分信息:
实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承的还是在子类定义的,都要记录下来。
不是必须的,也没什么特别含义,它仅仅起着占位符的作用。