一、概览
在Hotspot虚拟机中,java对象在内存中分布如下图所示:
+---------------+---------------+---------------+
| 对象头 | 实例数据 | 对齐填充 |
+---------------+---------------+---------------+
对象大小 = 对象头 + 实例数据 + [填充数据]
- 对象头:任何对象都包含对象头,用于存储该对象的class类型指针、GC年龄、HashCode、锁标志等信息;
- 实例数据:业务定义的数据;
- 对齐填充:
- java规定内存默认使用8字节对齐,方便寻址,提升效率(以空间换时间);
- 该部分不是必需的,即前面对象头和实例数据的大小之和不是8的倍数(8N),则补齐空间到8N;否则,无需对齐填充部分。
- 对齐8字节这个参数可以通过JVM参数
-XX:ObjectAlignmentInBytes
来改变(默认值为8)。当然这个数值的必须是2的次幂,数值范围需要在8 - 256之间。
二、代码实例
2.1、 准备工作
- 为了方便我们查看java对象内存分布,我们需借助 jol(Java Object Layout)这个小工具;
- jol maven坐标
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.10</version>
</dependency>
2.2 、代码
import org.openjdk.jol.info.ClassLayout;public class Head {public static void main(String[] args) throws InterruptedException {System.out.println("查看 Empty 对象");System.out.println(ClassLayout.parseInstance(new Empty()).toPrintable());System.out.println("查看 UserPadding 对象");System.out.println(ClassLayout.parseInstance(new UserPadding()).toPrintable());System.out.println("查看 UserNoPadding 对象");System.out.println(ClassLayout.parseInstance(new UserNoPadding()).toPrintable());}static class Empty{}static class UserPadding{int age; // 4个字节long date; // 8个字节String name; // 4个字节}static class UserNoPadding extends UserPadding{int salary;}
}
2.3、运行结果
附:
- OFFSET:表示偏移量
- SIZE:占用字节大小
- TYPE:具体类型
- DESCRIPTION:字段名称;
(object header)
为对象头 - VALUE:取值,基本类型存的就是实际值,引用类型存的是指针
- 当前运行jvm为 64-bit HotSpot VM
2.4、分析
2.4.1、Empty
对象
- 对象头:占用12(4+4+4)字节
- 实例数据:占用0(该对象没有业务数据)
- 对齐填充:前面一共占用12(12 + 0)字节,填充4字节使得整个对象占用16字节,对齐8N;
2.4.2、UserPadding
对象
- 对象头:占用12(4+4+4)字节
- 实例数据:占用16字节(int 4字节,long 8字节, String 4字节指针)
- 对齐填充:前面一共占用28(12 + 16)字节,填充4字节使得整个对象占用32字节,对齐8N;
2.4.3、UserNoPadding
对象
- 对象头:占用12(4+4+4)字节
- 实例数据:占用20字节(2个 int 8字节,long 8字节, String 4字节指针)
- 对齐填充:前面一共占用32(12 + 20)字节,已经对齐8N,无需填充;
2.4.4、业务数据的默认值
观察UserPadding
对象的业务数据默认值(用户并未显示指定值),可以看到:
- 数据类型默认为
0
; - 引用类型默认
null
。