如何估算一个对象的大小?
为什么突然会想起这个话题,主要是因为在excel对象等导入导出,或者从数据库中查询出较多的对象时,预估下所占内存的大小,预估风险。
一、Java对象内存布局
要想预估java对象的大小,首先要明确对象内存结构是由哪几部分组成。
一个Java对象主要包括:对象头(Header),实例数据(Instance Data),对齐填充(Padding)。
如下图:
对象内存结构.png
查看是否开启压缩
java -XX:+PrintCommandLineFlags -version
image.png
所以说
默认是开启压缩的
当然也可以通过代码,获取一个对象的布局信息。
引入jol 的 maven坐标
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
执行以下代码:
public static void main(String[] args) {
User user = new User();
user.setAge(18);
user.setName("zhaosc");
System.out.println(ClassLayout.parseInstance(user).toPrintable());
}
image.png
添加-XX:-UseCompressedOops -XX:-UseCompressedClassPointers参数之后,即去掉压缩,执行。
执行结果如下:
image.png
其中:
- mark:代表自身运行时的数据(Mark Word),8byte
- class:代表类型指针(Class Pointer),8byte
- age,name为实例数据,12byte
- padding:对齐填充, 4byte
既然知道了Java对象内存布局结果,那么如何估算一个对象的大小呢?
对象大小=对象头+实例数+对齐填充
所以关键在于实例数据的计算。
二、实例数据计算
2.1 基本类型的计算
一个Java类的属性值,可能是基本类型或引用类型两种,所以先看简单的基本类型所占内存大小
类型 | 二进制位数 | bytes |
---|---|---|
boolean | 1 | 1 |
byte | 8 | 1 |
char | 16 | 2 |
short | 16 | 2 |
Int | 32 | 4 |
long | 64 | 8 |
float | 32 | 4 |
double | 64 | 8 |
引用类型指针 | 64或32 | 在32位系统上每个占用4bytes;在64位系统上每个占用8bytes,开启指针压缩后占用4个 |
2.2引用类型的计算
引用类型的计算相对于基本类型的计算来说,比较麻烦。
大致思路是:将引用类型,转换为基本类型,一个引用指针占用4个字节,对象头占用12个字节(因为默认开启压缩),如果数组,再加上4个字节的数组长度,不是8的倍数,对齐补充
-
java.lang.Integer
它是int的包装类型的包装类型,所以Integer长度为:头(8+4)+ int(4) = 16字节。
其他Long、Double等类似。 -
java.lang.String
image.png
String="zhaosc";
它是得底层是char数组结构。
String类型:头部(8+4)+int(4)+指向char[]对象的引用类型(4)+padding(4)=24字节
char[]类型:头部(8+4)+数组长度(4)+“zhaosc”(2*6)+padding(4)=32字节
因此,它的总占用空间为32+24=56字节,56*8=448bit
-
自定义类 com.zhaosc.User
public class User {
private String name;
private int age;
}
还是以
User user = new User();
user.setAge(18);
user.setName("zhaosc");
User类型:头部(8+4)+int(4)+String的引用类型(4)+padding(4)=24字节
String类型:头部(8+4)+int(4)+指向char[]对象的引用类型(4)+padding(4)=24字节
char[]类型:头部(8+4)+数组长度(4)+“zhaosc”(26)+padding(4)=32字节
所以一共是24+24+32=80字节,808=640bit
网友评论