此心光明,亦复何言
『Everything is an object in java』在Java中,万物皆是对象。在我们日常工作中,我们都知道所谓的『对象』就是 Object 以及继承自Object的类的实例。另外我们也知道Java的对象都是存储分配在堆上的。(PS:这里不讨论JVM的优化内容)
开发这么过年,你优化性能的时候肯定考虑过一个对象的大小,但是你有没有想过堆上到底存储的是什么?这里的两个问题:
- 对象所占内存的大小;
- 对象在内存中的样子;
如果不知道What,就开始来猜大小,这就纯属XJB猜…
团长说了:『硬仗没你这打法,你小子不能只玩楞的』
带着这些疑问,这就正式进入本篇文章的话题,
1. 对象内存布局(Java Object Memory Structure)
我们先要弄明白对象在内存长什么样子,要想搞明白这个问题,
1.1 两种对象
在内存中,对象分为两种:
- 普通对象;
- 数组对象;
1.2 对象的构造
在JVM中,Java对象在内存中存储的布局可以分为下面几块区域:
- 对象头(Object Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
- 数组长度 (PS: 数组对象独有)
1.2.1 对象头
对象头又分为两部分:
- 标记字段(Mark Word):主要包含对象的身份(hashCode)以及一些标志位(锁,分代年龄等)
- Class对象指针(Class Pointer): 指向对象所对应的Class对象的内存地址
1.2.2 实例数据
即类中我们所定义的『成员变量』。友情提示:static修饰的变量不属于对象的内容。
1.2.3 对齐填充
Objects are 8 bytes aligned.(因为Java中所有的对象都要求8字节对齐,不够8字节的需要填充)
1.2.4 数组长度
该区域是数组对象独有的,见名知意,就是用来表示该数组对象的长度(元素个数)。
1.3 一图胜千言
下面这个图应该能满足你的需求吧。
2. 验证结论
这里为了能看清普通对象和数组对象的区别,定义没有任何成员变量的类.
2.1 普通对象
public static class Empty{}
public static void main(String[] args) {
Empty instance = new Empty();
System.out.println(ClassLayout.parseInstance(instance).toPrintable());
}
结果如下:
2.2 数组对象
public static void main(String[] args) {
Empty[] arr = new Empty[10];
System.out.println(ClassLayout.parseInstance(arr).toPrintable());
}
public static class Empty{}
结果如下:
3 总结
通过上面的结论,我们可以清楚的看出对象在内存中的结构以及所占的内存大小。惊不惊喜,意不意外… 在下一篇文章中,我将揭露这其中所不为人知的秘密。