✅JVM是如何创建对象的?
典型回答
- 首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程
- 分配内存。JVM会在堆中为对象分配内存空间(无JIT优化情况下)。在HotSpot中,对象的内存分配有两种方式,分别是指针碰撞和空闲列表法。
- 指针碰撞:当堆中的内存是连续的,JVM使用一个指针来标记当前可用的内存位置,然后将指针向前移动分配对象所需的内存大小。
- 空闲列表:当堆中的内存是离散的,JVM会维护一个空闲列表,记录可用的内存块。在分配对象时,JVM会遍历空闲列表,找到足够大小的内存块进行分配。
(分配内存解决并发有两种手段,一个是CAS+失败重试,一个是Thread Local Allocation Buffer(TLAB))
- 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值,这一步确保了对象的字段在创建时都有默认值。如int被初始化为0,引用类型被初始化为null
- 设置对象头。 该实例所对应的类、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄,轻量级锁等等信息
- 调用该类的构造方法,初始化对象。如按照程序员意愿进行赋值
- 返回对象引用,当对象完成创建之后,返回一个该对象的引用,后续Java程序就可以使用这个引用来操作对象了。
知识扩展
指针碰撞和空闲列表法的区别?
Java在分配内存的时候,会根据堆是否规整来选择指针碰撞法或者空闲列表法
指针碰撞法即是通过一个指针将内存划分为已经分配过的空间和没有分配过的空间,如果要给新对象分配空间,则需要先计算出来该对象应该占用的空间,然后指针向前移动分配对象所需的内存大小,然后返回分配前的指针位置作为对象的起始地址。由此我们可见,指针碰撞法适合堆内存规整的区域,对应着Serial,ParNew GC等垃圾回收器。同时也对应着标记整理算法,复制算法等GC算法

空闲列表法,故名思义,和列表有关。JVM会维护一个列表,其中会记录堆中哪些内存可用,哪些内存不可用,这样在申请内存空间的时候,只需要找到一块可用的内存,并在列表中标记即可。由此可见,该方法适合堆内存不规整,对应的GC算法为标记清除算法。其中CMS GC实现了该算法
指针碰撞适用于堆内存连续的情况,它简单高效,但对内存的要求较高。空闲列表适用于堆内存离散的情况,它可以更灵活地利用内存碎片,但需要额外的空间来维护和查找空闲内存块。
TLAB
✅JVM如何保证给对象分配内存过程的线程安全?
原文: https://www.yuque.com/hollis666/xkm7k3/yx27u8