在上篇文章中介绍一个对象的组成部分主要分为三部分。对象头、实例数据、填充对齐。实例数据。这里我们就继续分析这三部分中具体的组成情况。
为了证实一个对象存在这3个部分。这里 使用 JOL( java object layout 是分析 JVM 中对象布局的工具,该工具大量使用了 Unsafe、JVMTI 来解码布局情况)来分析。这里使用0.16版本。目前市面的电脑绝大多数多是64位操作系统,这里也基于64位操作系统来展开讲解,32位的大家知道就可以了。本人电脑操作系统 MacOS Monterey 12.2.1。
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
Hotspot 虚拟机文档 “oops/oop.hp” 有对 Markword 字段的定义
Bit-format of an object header (most significant first, big endian layout below):
32 bits:
--------
hash:25 ------------>| age:4 biased_ lock :1 lock:2 (normal object)
Java Thread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
size:32 ------------------------------------------>| (CMS free block)
PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
64 bits:
--------
unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
size:64 ----------------------------------------------------->| (CMS free block)
unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
理论上一个空对象的大小为对象头大小12字节(Markword 8字节、class pointer 4字节),考虑到8 字节对齐 填充,需要补齐4字节为8 的2倍16字节。
我们来new一个空对象
public class AnalysisObject {
}
使用JOL分析AnalysisObject对象信息
public static void main(String[] args) {
AnalysisObject object = new AnalysisObject();
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
输出结果信息
com.github.sylphlike.web.AnalysisObject object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x000000000000000d (biasable; age: 1)
8 4 (object header: class) 0x00066a48
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
表头依次为 OFF:在内存中的起始位置 SZ:占用大小(字节)TYPE DESCRIPTION: 类型 VALUE:具体值
(object header: mark) 对应MarkWord,占用大小8 byte
(object header: class) 对应 class pointer 占用大小4byte
(object alignment gap) 对应 Padding 占用大小为4
Instance size 对象占用的总字节数大小
Space losses 对应对齐填充大小
接下来我们给对象添加一下属性方法。
public class AnalysisObject {
private String s;
private int i;
private boolean b;
private double d;
private Integer in;
public void method(){}
}
输出结果信息
com.github.sylphlike.web.AnalysisObject object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x000000000000000d (biasable; age: 1)
8 4 (object header: class) 0x00066a48
12 4 int AnalysisObject.i 0
16 8 double AnalysisObject.d 0.0
24 1 boolean AnalysisObject.b false
25 3 (alignment/padding gap)
28 4 java.lang.String AnalysisObject.s null
32 4 java.lang.Integer AnalysisObject.in null
36 4 (object alignment gap)
Instance size: 40 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
从结果中看出对象占用40字节大小。Instance size: 40 bytes. 一共5个属性,一个方法。int占4字节、boolean占1字节、double占8字节、 Integer 和 String 为引用类型所以占4字节。
从上面结果中我们还发现有两种填充方式 3 bytes internal 和 4 bytes external. 为什么存在两种填充方式?这里先给出结论。后面再探讨该问题;出现(alignment/padding gap)有以下两种情况
1、如果都是基本数据类型,只有当不存在4字节的,或者小字节加起来填不满4字节,且所有字节和大于4的时候触发alignment/padding
2、如果实例数据存在非基本数据类型,也就是引用数据类型,先罗列并计算所有的基本类型数据的字节和,如果字节和不是4的倍数,那么此时会触发alignment/padding。
Markword中存放的数据在对象的整个 生命周期 内都是非常关键的,放在后后一篇文章中单独来阐述。