内存分配方式主要分为两种 分别是 指针碰撞空闲列表

指针碰撞指的是线性空间,通过移动指针分配内存。

空闲列表指的是不同的内存块,通过指针链接到一块完整从而继续分配。

解决内存分配存在线程不安全的方法是:

1、采用CAS机制+失败重试。

2、为每个线程预先分配一小块内存,称为本地线程分配缓冲内存,虚拟机在这块内存上赋初值。

 


对象在内存中的存储布局可分为 对象头(header)实例数据(Instance Data)对齐填充(Padding)

对象头分为两个部分,一部分用于存储对象自身的运行时数据如hashcode,GC分代年龄,锁状态,线程持有的锁、偏向线程ID、偏向时间戳等等,称为“MarkWord”

另一部分为类型指针,指向它类元数据的指针、从而确定对象是属于哪一个类。(若是Java数组还需要一块空间存储数据大小,因为虚拟机只能知道对象大小)

对齐填充只在需要的时候存在,目的是填充对象大小至8字节的整数倍。

 


对象的访问定位

在栈中的Ref可通过句柄或者直接指针指向对象

句柄方式:Ref->句柄池中的句柄->对象实例数据(Java堆)

->类型数据(方法区)

直接指针方式:Ref->对象实例数据(Java堆)->对象类型数据(方法区)

句柄采用二次定位 在对象移动时,只需要改动句柄而不需要改动Ref

直接指针直接访问对象,效率更高,不用二次寻址。


给每个线程的内存有限(Window限制每个线程最多2G)若因线程过多导致的SOF异常,可采取减少最大堆和分配给线程的栈容量来获得更多线程。

方法区和运行时常量溢出只能通过缩减其他内存区域或者优化GC对方法区的回收来保证。

KAI Java