对象创建
对象的创建流程
类加载检查
判断有无加载过该类,有则直接进入下一步、没有则加载类对象。
分配内存
虚拟机为新生对象分配内存。
对象所需内存大小在类检查阶段便可确定,为对象分配空间就是将一块确定大小内存从 Java 堆中划分出来。
1. 划分内存的方法
指针碰撞法
该方法是JVM中的默认方法。
它主要就是假设JVM中的内存是绝对规整的,使用过的内存和未使用过的内存分别放在两边,用一个指针来给他们做区分。如果要分配内存,只需要将指针向空闲的那一端移动对象大小的位置就好了。
空闲列表
如果JAVA堆中的内存分配并不是规整的,那么就需要一张表来记录某些还未分配的内存大小,当需要进行内存分配的时候从表中找到足够大小的内存区域来完成分配,并更新列表上的区域。
2. 解决并发问题的方法
在并发情况下,可能出现多个对象引用同一块内存地址的问题。
CAS
虚拟机默认使用 CAS 配上重试失败的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理。
本地线程分配缓冲(TLAB)
每个线程在堆上分配一块区域,将内存分配按照不同的线程进行。
初始化
分配完成之后虚拟机需要将分配完成的对象空间都初始化为零值(不包括对象头)。
设置对象头
初始化零值之后、虚拟机要对对象做一些必要的设置,这些设置是用来帮助虚拟机管理这个对象的。
执行init方法
对象按照程序员的意愿进行初始化,也就是给属性赋值(代码中的值)并执行构造方法。
堆内存中的对象实例
对象头
存储对象自身的运行时数据。
哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
存储类型指针。
即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
实例数据
具体的实例对象数据。
对齐填充
保证对象是 8 个字节的整数倍。
对象指针压缩
减少内存消耗
指针压缩可以减少每一个堆对象的大小,让同样的内存大小可以放更多的对象,这样就会使得内存存储的数据更多的情况下才会触发GC。(指针压缩在JDK1.6之后是默认开启的)