内存分配:
为对象分配内存有两种方式, 第一种是 "指针碰撞", 也就是把内存分为两边, 一边是已使用区域, 另一边是未分配区域, 分界线用指针记录, 当要分配内存时, 只需把指针向未分配区域移动需要的空间即可, 通常 compact 算法的垃圾回收会使用 "指针碰撞", 如 Serial,ParNew; 另一种是空闲列表记录, 也就是分配是可以不连续的, 中间很多间隔可用的未分配内存, 这个时候需要一个列表来对内存进行记录, 分配内存时候就在列表找到最合适的, 通常这种分配方式对应的垃圾回收器如 CMS 这种基于 Mark-Sweep 算法;
由于分配内存也是多线程, 存在内存使用资源的竞争, 因此要保证线程安全, 解决这个问题有两种方案, 第一种是利用 CAS 加上失败重试方法保持原子性; 第二种是用到 ThreadLocal 思想, 就是为每一个线程分配一个线程自己的空间, 称为 Thread Local Allocation Buffer,TLAB, 当线程完成逃逸分析后就把对象分配到该区域内. 最后, 当线程分配完后虚拟机就马上为分配到的空间初始化为零值, 不包括对象头.
对象头 (Header):
对象可以分为三部分, 对象头, 实例数据, 对齐填充;
对象头包括两种信息, 第一是运行时数据 (Mark Word), 第二是类型指针 (用作指定该对象是哪个类创建的, 但也不一定就这样实现); 运行时数据包括: 哈希吗, GC 分代年龄, 锁状态标志, 线程持有的锁, 偏向锁 ID, 偏向时间戳等等. 如果该对象是数组, 那么还会对象头还会继续数组大小的数据.
然后就是真正的实例数据了, 实例数据包括父类继承下来的和子类拥有的, 会优先安排父类的字段排序在前面, 同时会根据基本类型的大小, 把大小相同的放到一起分配. 最后的数据对齐就是简单的填充作用.
,,,,, 待续
来源: http://www.bubuko.com/infodetail-2570639.html