在Java开发中我们经常会接触到Integer这个包装类,我们经常说Integer
占用4个字节,32比特,其数据的表示范围是-2^31 ~ 2^31-1
之间,但是作为一个实例对象存在时,真实情况只是这样吗?
这里我们需要用到一个工具,JProfile
。
一个空对象的大小
这里请尝试运行下面的代码
public class TestInteger {
public static void main(String[] args) {
TestObject testObject = new TestObject();
Scanner scanner = new Scanner(System.in);
scanner.next();
}
}
class TestObject {
}
此处我们创建了一个空对象,现在我们打开工具看一下一个空对象所占用的内存

可以看到内存占用为16bytes
,这里我们需要了解一些概念,也就是一个java对象的组成结构,请看下面这张图:

一个非数组实例由三部分组成,对象头,对象实际数据以及可能存在的对齐填充。
对象头
HotSpot
虚拟机的对象头包含两部分信息:
- 第一部分
markword
中储存了该实例的哈希码、GC分代年龄、等待队列、EntrySet、偏向线程ID、偏向时间戳、对象状态,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,官方称它为“MarkWord”。 - 对象头的另一部分是kclass,类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.
实例数据
真正储存数据的部分
对齐填充
HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,也就是说,不足8字节倍数部分需要补上。
了解完这些知识后,我们再来解释一下为什么一个空对象占用的字节数为16字节。
在Java8
中的hotspot
虚拟机默认开启了指针压缩,因此一个空对象的实际大小为
12字节的对象头 + 4字节的对齐 = 16字节
这也验证了我们之前工具所获得的结论。
//禁用指针压缩的jvm指令
-XX:-UseCompressedOops
一个Integer对象的大小
现在,让我们测试一下一个Integer对象的大小,代码很简单
class TestObject {
private Integer i = 128;
}
这次得到的测试结果如下图所示,这里还有一个概念,关于RetainedSize 与 Shallow Size。

因为我们的对象头已经占用了16字节的空间,那么显然Integer也占用了16字节的大小,计算方式如下
12字节的对象头 + 4字节的实际储存空间 = 16 字节
其它类型的大小各位看官有兴趣的话可以自行尝试一下。
字数:303
发布于 1 年前