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

OOP模型、计算java对象大小

程序员文章站 2022-07-12 16:50:18
...

OOP模型

oop是java对象在jvm中的存在形式。

OOP模型、计算java对象大小

一个oop对象分为 对象头区域,实例数据区域,对其填充这三部分。

OOP模型、计算java对象大小

对象头

对象头区域分为三部分,Mark Word,类型指针,数组长度。

  1. Mark Word:标记字。主要用来表示对象的线程锁状态,存放对象hashCode、GC次数

    ​ 32bit占用:4B

    ​ 64bit占用:8B

  2. 类型指针(Klass pointer):指向Class信息的指针,表示该对象是哪个Class的实例

    ​ 开启指针压缩:4B

    ​ 关闭指针压缩:8B

  3. 数组长度,当对象不是数组对象时,该区域不占空间。

    ​ 默认占用4B

实例数据

​ 类的非静态属性,生成的数据就是对象的实例数据

​ byte:1B

​ short:2B

​ int:4B

​ long:8B

​ double:8B

​ float:4B

​ char:2B

​ boolean:1B

​ ref:

​ 32位 4字节

​ 64位 8字节

​ 64位如果使用指针压缩就是 4字节

对象填充区域

​ 默认8字节对齐。当一个对象的大小不足8的整数倍的时候。会填充字节。

​ 假如一个对象是30字节,会默认填充2个字节,达到8字节对齐。

计算对象大小

以下测试都是在开启指针压缩下测试,单位是字节byte

​ 使用jol验证计算正确

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>

普通对象

​ MarkWord KlassPointer 数组长度 实例数据 对齐填充

​ 8 + 4 + 0 + 0 +4 =16

public class TestOOP {
    public static void main(String[] args) {
        TestOOP testOOP = new TestOOP();
        System.out.println(ClassLayout.parseInstance(testOOP).toPrintable());
    }
}

OOP模型、计算java对象大小

带属性对象

​ 静态变量不占用oop的内存空间

​ MarkWord KlassPointer 数组长度 实例数据 对齐填充

​ 8 + 4 + 0 + 4+ 4+4 +0 =24

public class TestOOP {
    static int i = 0;
    int b = 1;
    int c = 1;
    String a = "1";

    public static void main(String[] args) {
        TestOOP testOOP = new TestOOP();
        System.out.println(ClassLayout.parseInstance(testOOP).toPrintable());
    }
}

OOP模型、计算java对象大小

String对象

​ MarkWord KlassPointer 数组长度 实例数据 对齐填充

String对象 8 + 4 + 0 + 4+ 4+4 +0 =24

字符数组 8 + 4 + 4 + 2+ 2+2+2+2 +6 =32

所以"hello"占用58个字节

计算公式 24(String对象)+ (16+字符串长度*2+填充)

 System.out.println(ClassLayout.parseInstance("hello").toPrintable());
 System.out.println(GraphLayout.parseInstance("hello").toPrintable());

OOP模型、计算java对象大小

ArrayList对象

​ ArrayList底层用的 Object[] elementData 数组维护的数据。

​ MarkWord KlassPointer 数组长度 实例数据 对齐填充

ArrayList 8 + 4 + 0 + 4+ 4+4 +0 =24

elementData[] 8 + 4 + 4 + 4*10(数组占用空间) +0=56

ArrayList在不存储数据的情况下elementData[]不占用空间,只要add一个元素,数组长度就最少为10,所以占用80个字节,扩容情况下另行计算

“1” 字符串占24+(16+2+6)=48

Integer类型占用的空间 16

占用24 +56 + 48 +16 =144

ArrayList<Object> list = new ArrayList<Object>();
list.add("1");
list.add(1);
System.out.println(ClassLayout.parseInstance(list).toPrintable());
System.out.println(GraphLayout.parseInstance(list).toPrintable());
System.out.println(GraphLayout.parseInstance(list).totalSize());

OOP模型、计算java对象大小

HashMap对象

​ HashMap用的是Node[] 数组维护的数据。

OOP模型、计算java对象大小

​ Node对象中有四个属性,其中一个int类型。三个引用类型

OOP模型、计算java对象大小

​ MarkWord KlassPointer 数组长度 实例数据 对齐填充

HashMap 8 + 4 + 0 + 4*8 +4 =48

Node[] 8 + 4 + 4 + 4*16 +0 =80

HashMap在不存储数据的情况下Node[] 不占用空间,只要put一个元素,数组长度就最少为16,所以占用128个字节,扩容情况下另行计算

Node[0] 8 + 4 + 0 + 4*4 +4 =32

Node[1] 8 + 4 + 0 + 4*4 +4 =32

加上字符串的占用空间 48+48 两个"1" 会在字符串常量池,只记录一个在内存

Integer类型占用的空间 16

总共 128+ 32 + 32 + 48 +48 +16 =304

 HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("1","1");
    map.put("2",2);
    System.out.println(ClassLayout.parseInstance(map).toPrintable());
    System.out.println(GraphLayout.parseInstance(map).toPrintable());
    System.out.println(GraphLayout.parseInstance(map).totalSize());

OOP模型、计算java对象大小

OOP模型、计算java对象大小

相关标签: jvm