一个对象通常由头和内容组成。想要计算一个对象的大小,我们就需要分别计算头部的大小和内容的大小。
查看一个对象的大小
首先在pom文件中引入apache下面的lucene-core依赖,然后调用对应的shallowSizeOf()方法。
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>6.6.1</version>
</dependency>
public class Test {
public static void main(String[] args) {
Integer integer = new Integer(10);
System.out.println(RamUsageEstimator.shallowSizeOf(integer)); //结果为16
}
}
可以看到Integer对象的大小是16个字节。
头部大小
对象的头通常会存储该对象地址,标记(里面存储有该对象的锁,hashcode,年龄等信息)等信息。其中,地址会占用4个字节,标记会占用8个字节。也就是说,一个对象的头部默认会占用4+8=12个字节。另外,如果该对象是一个数组的话,头部还需要额外的4个字节来存储该数组的长度(因为JVM使用一个int类型的变量来记录数组的长度,而int类型长度为4个字节)。也就是说,对于一个数组对象的话,它的头部会占用4+8+4=16个字节。
内容大小
为了计算内容大小,我们需要查看该对象的类内部的方法和变量。以上面的Integer对象为例,进入其代码中我们可以看到大部分的变量都是用static来修饰的,这样的变量会被存在方法区,并不算做Java对象的大小。除此之外,类的方法也是存储在方法区的,也不会被计算。
而该Integer对象的值是用int变量来存储的,并没有用static修饰,这意味着value变量将占用4个字节。
因此,一个Integer对象的大小就是4+8+4=16个字节,这也和上面程序输出的大小一致。
注意点
需要注意的是,由于Java的存储是以8字节为单位扩展的,所以Java的对象的大小都是8字节的整数倍。如果头部+内容的大小不是8的倍数,将自动补充为8字节的整数倍。如Hashmap占用48个字节,但是实际上看代码Hashmap只占用了44个字节,这就是因为44字节自动填充为了48字节。