java n占用字节_史上最详细java对象占几个字节?

一、下载工具

要想分析某个对象大小,要借助一个工具jol-core,他的maven地址是:

 org.openjdk.jol jol-core 0.9

二、测试

首先新建一个空类,里面不包含任何字段。然后使用jol-core打印一下对象布局。

public class Dog {}public class App{public static voidmain( String[]args){Dogdog=new Dog();System.out.println(ClassLayout.parseInstance(dog).toPrintable());}}

他将输出如下信息,在最后,有一条信息为"Instance size: 16 bytes",也就是说这个对象是16个字节。

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 44 c1 00 f8 (01000100 11000001 00000000 11111000) (-134168252) 12 4 (loss due to the next object alignment)Instance size: 16 bytes

三、对象内存布局

要说这16个字节哪来的,就得先了解java对象的内存布局,也就是如下图。对象的内存布局分为对象头、对象中实际数据、对其填充。先不讨论这三个干什么用,只需要知道他们分别占几个字节就行了,毕竟本文只说对象大小。

8f241e6e60eefffda2090b1424cf1894.png

3.1 对象头大小

第一部分是对象的脑袋,分为Mark Word和Class Pointer,在不同位数的JVM有不同的大小。

在32位系统上,Mark Word是4字节,Class Pointer也是4字节,总共是8字节。

在64位系统上,受指针压缩影响,开启指针压缩时Mark Word是8字节,Class Pointer是4字节,总共12字节。关闭指针压缩Mark Word是8字节,Class Pointer也是8字节。

3.2 指针压缩

在64位上有一个指针压缩的概念,参数为XX:+UseCompressedOops,默认是开启的,开启后Class Pointer将被压缩为4字节,对象头最终共为12个字节。

64位JVM测试

开启指针压缩时输出(默认就是开启),不用管,最终大小为16字节。

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 44 c1 00 f8 (01000100 11000001 00000000 11111000) (-134168252) 12 4 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

接着测试关闭指针压缩,在IDEA中点击运行配置,VM options中输入-XX:-UseCompressedOops,代表关闭指针压缩。

fef12c84614348a0b47aa887881b95d7.png

结果输出如下

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header)                           e0 e4 e0 94 (11100000 11100100 11100000 10010100) (-1797200672) 12 4 (object header) 07 7f 00 00 (00000111 01111111 00000000 00000000) (32519)Instance size: 16 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes total

你会发现最终大小都是16字节,但是开启压缩时有一行 (loss due to the next object alignment)大小为4字节,这个表示对齐填充,这是因为人家设计时就要求大小为8的倍数,原本12不是8的倍数,所以自己又填充了4。对齐填充没有其他意义,只为了数据对齐,保证是8的倍数。

32位JVM测试

需要下载一个32位jdk。然后快捷键Ctrl+Alt+Shift+S打开项目配置,选择32位的jdk路径。

d205c5abaef332df7b585235831a534d.png

结果为8个字节,也不需要数据对其。

com.hxl.entity.Dog object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header)                           e0 c5 cd a3 (11100000 11000101 11001101 10100011) (-1546795552)Instance size: 8 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes total

3.3 实际数据

在Dog中增加一个整形和cha类型的字段。

public class Dog { private int age; private char date;}

64位JVM测试

此时在开启指针压缩情况下输出:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 44 c1 00 f8 (01000100 11000001 00000000 11111000) (-134168252) 12 4 int Dog.age                                   0 16 2 char Dog.date                                    18 6 (loss due to the next object alignment)Instance size: 24 bytesSpace losses: 0 bytes internal + 6 bytes external = 6 bytes total

因为int占4字节,char占2个字节,所以,原本的大小为12(对象头)+4(int)+2(char)=18,但是18不是8的倍数啊,所以要进行数据对齐,填了6个,18+6=24个字节。

在关闭指针压缩情况下输出:

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 10 a5 23 b7 (00010000 10100101 00100011 10110111) (-1222400752) 12 4 (object header) 22 7f 00 00 (00100010 01111111 00000000 00000000) (32546) 16 4 int Dog.age                                   0 20 2 char Dog.date                                    22 2 (loss due to the next object alignment)Instance size: 24 bytesSpace losses: 0 bytes internal + 2 bytes external = 2 bytes total

按照上面所说,原本大小为16(对象头大小)+4(int)+2(char)=22,还需填2个字节就是8的倍数了,所以上面输出(loss due to the next object alignment)是2个字节。

32位JVM测试

但是这一切的一切,在32位的JVM上输出如下,只有16个字节。32位没有指针压缩的概念,所以原本大小为8(对象头)+4(int)+2(char)=14,还要填充2字节为8的倍数。所以最终为16字节。

OFFSET  SIZE   TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 08 c6 cd a3 (00001000 11000110 11001101 10100011) (-1546795512) 8 4 int Dog.age                                   0 12 2 char Dog.date                                    14 2 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 2 bytes external = 2 bytes total

3.4 引用大小

在dog中增加name。

public class Dog { private String name;}

64位JVM测试

同样在关闭指针压缩时输出如下,发现引用类型占8字节。最终大小为24字节。

OFFSET  SIZE               TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header)                           f8 34 a0 2f (11111000 00110100 10100000 00101111) (799028472) 12 4 (object header) 3c 7f 00 00 (00111100 01111111 00000000 00000000) (32572) 16 8   java.lang.String Dog.name                                  nullInstance size: 24 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes total

开启指针压缩则不同了。引用类型占4字节。最终大小为16字节,也就是把引用类型压缩成4字节了。

OFFSET  SIZE               TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 44 c1 00 f8 (01000100 11000001 00000000 11111000) (-134168252) 12 4   java.lang.String Dog.name                                  nullInstance size: 16 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes total

32位JVM测试

32位上对象头8字节,引用类型占4字节。总共加上对其填充为16字节。

com.hxl.entity.Dog object internals: OFFSET  SIZE               TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header)                           f8 c5 dd a3 (11111000 11000101 11011101 10100011) (-1545746952) 8 4   java.lang.String Dog.name                                  null 12 4 (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

3.5 数组类型

但是如果对象是数组,在对象头中多出一条表示数组的长度。如下图,并且这个不受指针压缩影响,永远是4字节。

37136a38a31a66ea71743801a9e0ba22.png

如下代码。

Dog[] dogs ={new Dog()};

System.out.println(ClassLayout.parseInstance(dogs).toPrintable());

红色地方为数组的大小。

8ea3d32688a4eae983cb4f4ccc3808cc.png

数组分两种,基本数据类型数组和引用数据类型数组,基本数据类型数组计算方式为 (数组个数x单个元素大小),比如int数组,每个int是4字节,如果有5个元素,则数组占20字节。

但是引用类型就不一样了,开启指针压缩情况下为(数组长度x4),每个引用4字节,关闭后,每个引用8字节,占用(数组长度x8)字节。

如下,数组长度为8,每个引用8字节,最终占64字节(关闭指针压缩)。

Dog[] dogs ={new Dog(),new Dog(),new Dog(),new Dog(),new Dog(),new Dog(),new Dog(),new Dog()};System.out.println(ClassLayout.parseInstance(dogs).toPrintable());[Lcom.hxl.entity.Dog; object internals: OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 20 37 a0 93 (00100000 00110111 10100000 10010011) (-1818216672) 12 4 (object header) 11 7f 00 00 (00010001 01111111 00000000 00000000) (32529) 16 4 (object header) 08 00 00 00 (00001000 00000000 00000000 00000000) (8) 20 4 (alignment/padding gap)  24 64   com.hxl.entity.Dog Dog;.                           N/AInstance size: 88 bytesSpace losses: 4 bytes internal + 0 bytes external = 4 bytes total

在32位上则(数组个数x4)。如8个元素则是32字节。

如以上有错误地方,望多多指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值