内存分配方式:
指针碰撞:基于堆内存是绝对规整的,已使用的内存放在一边,未使用的放在另一边,中间放个指针,分配内存的时候,只要把指针向空闲内存移动与对象大小相等的位置即可。
空闲列表: 基于堆不是规整的,已使用和未使用的内存交互在一起,虚拟机需要维护一个列表,记录哪些内存是可用的,分配内存的时候,需要从列表中查找出一块足够大的内存分配给对象实例,然后更新列表记录。
选择哪种分配方式由java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集器是否具体空间压缩整理的能力
TLAB(Thread Local Allocation Buffer)
线程本地分配缓冲,虚拟机会为每个线程预先分配一小块内存,哪个线程需要分配内存,就直接在TLAB上分配。如果TLAB用完了,会向堆申请内存,此时需要同步(cas配上失败重试机制)。通过-XX:+/-UseTLAB设置是否使用TLAB
对象的内存布局
32位对象头
64位对象头
对象头:
Mark word:占用8个字节,包括hashcode、GC分代年龄、锁状态标志、线程持有的锁、偏向锁线程ID、偏向时间戳等。
类型指针:指向类元数据的指针。开启压缩指针占4个字节,未开启占8个字节
数组长度:占用4个字节。
对齐填充:条件是关闭压缩指针,并且对象里有数组元素
实例数据:存储对象数据
对齐填充:虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数,如果不够,需要通过对齐填充来补全。
对象的访问定位
直接指针:reference指向的是对象在堆中的地址。
句柄:reference指向的是句柄池地址,句柄池维护了对象实例数据指针和对象类型数据指针。