您的位置 首页 java

Java对象的字节大小计算

一、 java 基本类型长度及对应对象的字节长度

基本类型

长度(字节)

对象长度(字节)

int

4

16

short

2

16

long

8

24

byte

1

16

char

1

16

float

4

16

double

8

24

 System.out.println("Integer:" +  Class Layout.parseInstance(Integer.valueOf(122)).toPrintable());  

输出

  Integer :java.lang.Integer 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)                           64 22 00 f8 (01100100 00100010 00000000 11111000) (-134208924)
     12     4    int Integer.value                             122
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total  

二、对象内部组成

普通对象实例

对象头

身体

填充对齐

mark

class指针

对象实际数据

padding

数组对象实例

对象头

身体

填充对齐

mark

class指针

数组Length

对象实际数据

padding

注:数组实例对象中对象头多了一个记录数组长度的int类型对象,占4字节

对象头:

第一个部分mark,用于存储对象的运行时数据,比如 哈希码(hashCode)、GC年龄分代、锁状态标志、线程持有的锁、偏向 线程 id、偏向时间戳 等。 另外一部分class指针,即对象指向它的类元数据的指针, 虚拟机 通过这个指针来确定这个对象是哪个类的。

对象头占用空间:

1、在32位系统下,存放class指针的空间大小是4字节,MarkWork是4字节,对象头为8字节。

2、在64位系统下,存放Class指针的空间大小是8字节,MarkWordk是8字节,对象头尾16字节。

3、在64位开启指针压缩的情况下( -XX:+UseCompressedOops ),存放class指针的空间大小是4字节,markWord是8字节,对象头为12字节。

注:在开启指针压缩要求内存必须在4GB~32GB,因为32位指针寻址4GB,按8 字节对齐 , 4*8=32GB,按更大对齐可以寻址更大空间,但是浪费就更大了。

注:指针压缩不能压缩mark,指向非堆(Heap)的对象指针,局部变量、传参、返回值、NULL指针。

实例数据:

实例数据是 对象存储 的有效数据,也是程序代码中所定义的各种类型的字段内容,无论是从父类继承下来的,还是从子类中定义的,都需要记录起来。

对齐填充:

最后一块对齐填充空间并不是必然存在的,也没有特别的含义,它仅仅起着 占位符 的作用,这是由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是 8字节 的整数

空对象:

(此处的空对象是指类中没有任何基础类型和引用, 不是对象 = null)

 public class MyTest {
    @Test
    public  void  test(){
        A a = new A();      
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
class A{

}  

关闭指针压缩

-XX:-UseCompressedOops

类A没有值类型和引用类型 对象大小应该为 8(markword)+8(klass) 16byte

 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)                           f0 e2 ba 17 (11110000 11100010 10111010 00010111) (398123760)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
Instance size: 16 bytes  

开启指针压缩

对象大小应该为 8(markword)+4(klass)因为对象大小最后要能被8整除,所以还要所以还要+4的的填充对齐 ,最后大小还是16byte

  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)                           c8 16 01 20 (11001000 00010110 00000001 00100000) (536942280)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes  

注:64位系统内存大于4GB且小于32GB JVM 默认开启指针压缩。

三、普通对象

 public class MyTest {

    @Test
    public void test(){
        A a = new A();      
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
class A{
    int a;
    float b;
    long c;
    String d;
}  

关闭指针压缩:

对象大小应该是 8(markword)+8(Klass)+4(int)+4(float)+8(long)+8(string)(引用指针)40byte

  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)                           58 e3 e9 17 (01011000 11100011 11101001 00010111) (401204056)
     12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     8               long A.c                                       0
     24     4                int A.a                                       0
     28     4              float A.b                                       0.0
     32     8   java.lang.String A.d                                       null
Instance size: 40 bytes  

开启指针压缩:

对象大小应该是 8(markword)+4(Klass)+4(int)+4(float)+8(long)+4(string)(因为开启了指针压缩所以 引用指针 也是4byte)32byte

  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)                           c8 16 01 20 (11001000 00010110 00000001 00100000) (536942280)
     12     4                int A.a                                       0
     16     8               long A.c                                       0
     24     4              float A.b                                       0.0
     28     4    java.lang .String A.d                                       null
Instance size: 32 bytes  

开启/关闭指针压缩的结果区别:

主要区别就是让原本占用8字节的指针缩小到4字节,另外未开启指针压缩时,上面提到的基本类型内存填充将会以8对齐,开启时以4字节对齐。但是对象尾部的填充不管是否开启都是以8字节对齐。

使用网上找的 jar 有个弊端

可以使用 jdk 自带的jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; 可以评估出对象的大小。

System.out.println(“Integer:” + ObjectSizeCalculator.getObjectSize(Integer.valueOf(122)));

文章来源:智云一二三科技

文章标题:Java对象的字节大小计算

文章地址:https://www.zhihuclub.com/183396.shtml

关于作者: 智云科技

热门文章

网站地图