OOP模型、计算java对象大小

OOP模型

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

image.png

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

image.png

对象头

对象头区域分为三部分,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的内存空间

​ 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());
    }
}

在这里插入图片描述

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());

在这里插入图片描述

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());

在这里插入图片描述

HashMap对象

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

在这里插入图片描述

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

在这里插入图片描述

​ 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());

在这里插入图片描述

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值