一、对象的创建流程
二、对象的内存布局
在HotSpot(sun jdk和openJDK中所带的虚拟机,是目前使用最广的虚拟机)虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐信息(Padding)。
1、对象头
对象头包含两部分信息
第一部分(Mark Word)
用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
Mark Word数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit
- GC分代年龄
HotSpot使用分代垃圾回收机制,被分为三个代:年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。
(1)年轻代:所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。
(2)年老代:在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的
都是一些生命周期较长的对象。
(3)持久代:用于存放静态文件,如今Java类、方法等。
注意:Java8去除了持久代
- 锁状态标志
Mark Word的最后2bit是锁状态标志位,用来标记当前对象的状态。对象的所处的状态决定了Mark Word存储的内容,如下表所示:
状态 | 标志位 | 存储内容 |
---|---|---|
未锁定 | 01 | 对象哈希码、对象分代年龄 |
轻量级锁定 | 00 | 指向锁记录的指针 |
膨胀(重量级锁定) | 10 | 执行重量级锁定的指针 |
GC标记 | 11 | 空(不需要记录信息) |
可偏向 | 01 | 偏向线程ID、偏向时间戳、对象分代年龄 |
第二部分(类型指针)
对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
2、实例数据
实例数据是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
3、对齐填充
不必然存在,也没有特别的含义,仅仅起了占位符的作用。HotSpot VM 规定对象的大小必须是8字节的整数倍,当对象实例数据没有对齐时,需要对齐填充补全
三、对象的内存分配
Java自动内存管理最终可归结为自动化的解决了两个问题:给对象分配内存及回收分配给对象的内存。
- 对象优先在Eden(新生代Eden区)分配
如果Eden没有足够的空间分配,虚拟机将发起一次Minor GC - 大对象直接进入老年代
大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是很长的字符串以及数组。 - 长期存活的对象将进入老年代
每个对象有个年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1.对象在Survivor每熬过一次Minor GC,对象年龄加1。当对象到达15(默认15,通过-XX:MaxTenuringThreshold设置)的时候,将被晋升到老年代。 - 并不是所有对象年龄必须到达MaxTenuringThreshold才能晋升老年代
如果Survivor空间中,相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
四、其他
- Minor GC (新生代GC)
发生在新生代的垃圾收集动作,Minor GC非常频繁,回收速度快。 - Major GC / Full GC (老年代GC)
发生在老年代的GC,出现Major GC,经常会伴随至少一次的Minor GC(不绝对)。Major GC的速度一般比Minor GC 慢10倍以上。 - Eden 、 Survivor
新生代分为一个Eden区,两个Survivor区。Eden和Survivor的空间大小比例是8:1
[1] 周志明 · 深入理解Java虚拟机 :机械工业出版社
[2] GC分代相关概念摘自 https://www.cnblogs.com/weiguo21/p/5195460.html
[3] 锁状态标志相关摘自 https://blog.csdn.net/kirito_j/article/details/79201213