Java对象创建
创建的步骤
1 检查 对象类是否已经加载
虚拟机 遇到new指令时,检查 对象类是否已经加载,解析,初始化过,没有则执行类加载过程。
2 分配内存
类加载,检查通过后,开始为对象分配内存,
内存大小,在类加载后就已经确定了,
从Java堆中将内存划分出来,有两种方式
1 指针碰撞。Java堆内存是规整的,已用内存,可用内存是分开的,用一个指针作为分界点。分配内存就是将分界指针向可用内存方移动,指定大小内存,将该内存划分给对象。
2 空闲列表,Java堆内存是不规整的,已用内存和可用内存是交错的,虚拟机需要维护一个列表来记录那些可用,那些不可用。这样就需要从列表中找到一块足够大的内存,来划分给对象。
由于对象的创建是非常频繁的,分配内存需要考虑线程安全。解决这一问题有两种方式。
1 线程同步,对分配内存空间的动作进行同步处理,虚拟机采用CAS配失败重试方式保证更新操作原子性。
2 线程内存独立。每个线程在Java堆中预先分配一块内存,称为本地线程分配缓冲,(Thread Local Allocation Buffer TLAB),线程中的对象创建就使用该线程的TLAB,TLAB用完,需要划分新的TLAB空间是,还是需要线程同步。虚拟机是否使用TLAB 可以设参数来指定-XX:+/-UseTLAB
3 对象初始化
虚拟机首先将要分配到的内存空间都初始化为零值(不包括对象头),
** 对象的初始化也分为两个部分**
1 实例数据部分的初始化。对象的实例字段初始化为,字段类型所对应的零值,Numbic 对应为0,所有的对象为null,boolean类型为false;
2 对象头的初始化,对象头信息设置,例如这个对象是哪个类的实例,如何查找到类的元数据,对象HashCode,对象的GC分代年龄,等
4 调用<init>
** 其实经过以上三步,对于虚拟机而言,对象已经创建完毕,对于我们程序员而言,对象创建还刚刚开始。**
执行init方法,将所有的字段,按照我们程序员的意愿进行初始化,例如
1 | class Test{ |
对于Test这个类,经过3步后,a字段的值 为0,b为0,经过第四步后,a字段的值为 3, b先为4 然后为2
在main中输出的结果是 a:3,b2