欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-14 09:08:46
...

一、下载工具

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

<dependency>
  <groupId>org.openjdk.jol</groupId>
  <artifactId>jol-core</artifactId>
  <version>0.9</version>
</dependency>

二、测试

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

public class Dog {
}

public class App 
{

    public static void main( String[] args )
    {
        Dog dog =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对象的内存布局,也就是如下图。
对象的内存布局分为对象头、对象中实际数据、对其填充。
先不讨论这三个干什么用,只需要知道他们分别占几个字节就行了,毕竟本文只说对象大小。
史上最详细java对象占几个字节?

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 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

接着测试关闭指针压缩,在IDEA中点击运行配置,VM options中输入-XX:-UseCompressedOops,代表关闭指针压缩。
史上最详细java对象占几个字节?
结果输出如下

 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 bytes
Space 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路径。 史上最详细java对象占几个字节?
结果为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 bytes
Space 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 bytes
Space 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 bytes
Space 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 bytes
Space 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                                  null
Instance size: 24 bytes
Space 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                                  null
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

32JVM测试
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 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

3.5 数组类型

但是如果对象是数组,在对象头中多出一条表示数组的长度。如下图
史上最详细java对象占几个字节?
如下代码。

        Dog[] dogs ={new Dog()};
        System.out.println(ClassLayout.parseInstance(dogs).toPrintable());

红色地方为数组的大小。
史上最详细java对象占几个字节?
数组分两种,基本数据类型数组和引用数据类型数组,基本数据类型数组计算方式为 (数组个数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;.<elements>                           N/A
Instance size: 88 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

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

相关标签: Java