Redian新闻
>
对象很大,你忍一下

对象很大,你忍一下

公众号新闻

点击上方“芋道源码”,选择“设为星标

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 
来源:码海

Java 进阶之字节码剖析中我曾经提到这么一段话

int[128][2] ,int[256] 这两个数组看起来一样,但实际上前者比后者多了 246% 的额外开销

针对这句话我收到了几位读者的私信,表示不明白为啥不过一个简单的二维数组会有这么大的开销,本来这个问题在我正在写的类加载机制中有详述,不过文章还没写完(估计本周发),所以我专门抽出这个问题探讨一下,五分钟就能看懂。

Java 对象模型

HotSpot JVM 底层使用名为 oops (Ordinary Object Pointers) 的数据结构来表示对象的对象头

class oopDesc {
  friend class VMStructs;
  private:
    volatile markOop  _mark;
    union _metadata {
      Klass*      _klass;
      narrowKlass _compressed_klass;
    } _metadata;
    ...
}

JVM 每创建一个对象,相当于创建了一个 oopDesc 的对象,即 instanceOopDesc 来表示这个对象,保存在堆中,如下图所示

可以看到 Java 对应主要由以下三部分组成

  • 对象头(Header)
  • 对象实例数据(instance data)
  • 对齐填充(Padding)

其中对象头又包含三个部分

  • markWord:  即 _mark:markOop,用于存储对象运行时的数据,好比 HashCode、锁状态标志、GC分代年龄等。这部分在 64 位操作系统下占 8 字节,32 位操作系统下占 4 字节
  • 指针:指向方法区中的类元数据(类信息)的指针,这部分就涉及到指针压缩的概念,在开启指针压缩的状况下占 4 字节,未开启状况下占 8 字节,默认是开启的
  • 数组长度:这部分只有是数组对象才有,若是非数组对象就没这部分。这部分占 4 字节。

除此之外对象还有两个部分值得我们注意

  • 对象实例数据(instanceData): 用于存储对象中的各种类型的字段信息(包括从父类继承来的)
  • 对齐填充:Java 对象大小默认按 8 字节对齐的,如果「对象头」+「对象实际数据」不足8的位数,对齐填充会补齐相应的字节以让对象大小达到 8 的倍数

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

Java 数组大小

知道了对象模型的表示,再来看数组的大小,首先必须明确两点

  1. 在 Java 中数组是一种特殊的对象(也是对象,也有对象头)
  2. 一个多维数组是一个简单数组的数组,  例如,一个二维数组的每一行都是一个独立的数组对象

接下来我们来看看一维数组 int[256]  在内存中有多大,一维数组其实可以认为是普通的对象,首先对象头可以知道是 8(markword) + 4(kclass) + 4(数组长度)= 16 字节,对象实际数据大小为 256 * 4(int 大小为 4 个字节) = 1024  字节,所以此时总的字节数为 16 + 1024 = 1040 字节,是 8 的位数(1040/8 = 130),所以 padding 为 0, 也就是说 int[256] 一维数组的字节大小为 1040 字节

再来看一下二维数组 int[128][2] 的大小,我们知道在 C 语言中二维数组(事实上是任何多维数组)本质上是一维数组通过指针操作来实现的,但在 Java 中多维数组是由一系列的嵌套数组组成,也就是说对于二维数组而言,每一行(int[0][…],int[1][…],…,int[127][…])都对应一个数组对象,都需要额外的开销,一图胜千言,如下所示

先来看左边的对象大小:

数组的每一行 int[0],int[1],..int[127] 其实都是指向数组的指针,为 4 个字节,所以左边对象占用空间大小为 16 + 4 * 128 = 528,是 8 的倍数(528/8 = 66),所以 padding 为 0,所以总大小为 528

再来看左边的 int[0] 等指向的数组对象大小:

由于左边每个行数组的指向都指向了两个元素的数组(int[x][0],int[x][1]),它们的对象大小为  16 + 4 + 4 = 24,是 8 的倍数,所以 padding 为 0 ,而总共有 128 个这样的对象,所以右边总的对象大小为 128 * 24 = 3072

由此可知 int[128][2] 对象大小为 528 + 3072 = 3600 字节,比一维数组 int[256](1024 字节)多了 246% !

上述计算的是否正确呢,我们可以用 JDK 自带的 ObjectSizeCalculator 来计算一下,如下:

与我们的计算结果完全一致!

其实不光是二维数组,包括字节串,普通的对象开销也一般会比对象实际数据大几倍,到此我相信你不难明白上一篇中开头这样一段话的含义了:kafka 中为啥要使用 pageCache 了, 因为如果不用页缓存,而是用 JVM 进程中的缓存,对象的内存开销会非常大(通常是真实数据大小的几倍甚至更多)



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。

谢谢支持哟 (*^__^*)

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
你们会选择安逸但是工资低的工作还是压力很大但是回报高的工作?真想锤爆日本的头!这次对中国的影响很大,必须打击到底!看《奥本海默》前,你真得了解一下他剑桥大学学术活动资料包!48页,信息量很大,申请必备!给我5分钟,你的分析图还能再抢救一下!化妆不化妆差别很大,现在有点自卑不敢谈恋爱...赠书 | 这7本书,让你忍不住一口气读完!有本事,你动一下试试!不争不抢的汤唯却在戛纳红毯赢很大信息量很大!欧洲议会新冠肺炎峰会完整版术后疼痛要及时采取镇痛措施,忍一时可能演变为终生慢性疼痛!陈道明:人到中年,本事再大,你都争不过天道(深度好文)基辛格最新专访,信息量很大(下)骨科专家:它比跑步更毁膝盖!危害极大,你却天天在做…注意,超级英雄天团登陆加拿大,夏日炎炎,你 pick 谁?拜登预告中美下一步,中国回应信息量很大……世界唯一、日本第一的高尔夫观音菩萨小学成绩有很大的欺骗性,很多高分孩子到了初中就会掉队,是真的吗?一口爆浆,猫山王榴莲冰粽,一年只卖十几天,礼盒送人很大气!文革 - 血色,但不浪漫有些女人潜力很大,尤其是离婚后......猫爪必须在上!等一下,你是不是玩不起为啥阅读量很大,语文考试却很差?唉,你不看娃读的都是啥书呀……A股重磅!证监会刚刚发声,信息量很大!有一个非常“抠门”的对象,你该怎么办?贵州一客栈凌晨发生火灾,9人遇难!目击者:火势很大,一下冲起10多米信息量很大,华为刊发任正非最新内部讲话全文!冰岛Kirkjufellsfoss,热点风景​上海交大,你的吃相何必想那么难看?希腊游记:中学老师讲错了吗姚洋:这里我要批评一下美国人,你们太"浪漫"了四大秋招经验盘点:进入四大,你需要过多少关?普京终于宣布!这是一盘很大的局!我是个鸭,你忍一下咀外文嚼汉字(241)“借金渍”,日本借钱谚语
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。