热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java对象大小_一个Java对象到底占用多大内存?

最近在调研MAT和VisualVM源码实现,遇到一个可疑问题,两者计算出来的对象大小不一致,该信哪个?为了复现这个问题&#x

最近在调研MAT和VisualVM源码实现,遇到一个可疑问题,两者计算出来的对象大小不一致,该信哪个?

为了复现这个问题,准备了4个简单类:

class AAAAA {}

class BBBBB {

int a = 1;

}

class CCCCC {

long a = 1L;

}

class DDDDD {

String s = "hello";

}

再来个主函数:

final List aaa &#61; new ArrayList<>(100000);

final List bbb &#61; new ArrayList<>(100000);

final List ccc &#61; new ArrayList<>(100000);

final List ddd &#61; new ArrayList<>(100000);

for (int i &#61; 0; i <100000; i&#43;&#43;) {

aaa.add(new AAAAA());

bbb.add(new BBBBB());

ccc.add(new CCCCC());

ddd.add(new DDDDD());

}

本地环境是64位的JDK8&#xff0c;默认的启动参数&#xff0c;运行之后通过jmap -dump命令生成dump文件&#xff0c;分别用MAT和VisualVM打开。

MAT

通过MAT打开&#xff0c;可以发现ABD对象大小都是16字节&#xff0c;反而C对象大小为24字节

VisualVM

通过VisualVM打开&#xff0c;可以发现显示的大小和MAT的有蛮大的差别。

哪个才是正确的&#xff1f;

要回答这个问题&#xff0c;首先得清楚的知道JVM中一个对象的内存布局。

JVM中一个对象包含3个部分&#xff1a;对象头、实例数据和对齐填充。

对象头

这里不讲对象头是个什么东西&#xff0c;感兴趣的同学可以看我的其它文章。

对象头的大小一般和系统的位数有关&#xff0c;也和启动参数UseCompressedOops有关&#xff1a;32位系统&#xff0c;占用 8 字节

64位系统&#xff0c;开启UseCompressedOops时&#xff0c;占用 12 字节&#xff0c;否则是16字节

实例数据

原生类型的内存占用情况如下&#xff1a;boolean 1

byte 1

short 2

char 2

int 4

float 4

long 8

double 8

引用类型的内存占用和系统位数以及启动参数UseCompressedOops有关32位系统占4字节

64位系统&#xff0c;开启UseCompressedOops时&#xff0c;占用4字节&#xff0c;否则是8字节

对齐填充

在Hotspot中&#xff0c;为了更加容易的管理内存&#xff0c;一般会使用8字节进行对齐。

意思是每次分配的内存大小一定是8的倍数&#xff0c;如果对象头&#43;实例数据的值不是8的倍数&#xff0c;那么会重新计算一个较大值&#xff0c;进行分配。

结果

有了对象各部分的内存占用大小&#xff0c;可以很轻松的计算出ABCD各对象在64位系统&#xff0c;且开启UseCompressedOops参数时的大小。A对象只包含一个对象头&#xff0c;大小占12字节&#xff0c;不是8的倍数&#xff0c;需要加上4字节进行填充&#xff0c;一共占16字节

B对象包含一个对象头和int类型&#xff0c;12&#43;4&#61;16&#xff0c;正好是8的倍数&#xff0c;不需要填充。

C对象包含一个对象头和long类型&#xff0c;12&#43;8&#61;20&#xff0c;不是8的倍数&#xff0c;使用4个字节进行填充&#xff0c;占24字节

D对象包含一个对象头和引用类型&#xff0c;12&#43;4&#61;16&#xff0c;正好是8的倍数&#xff0c;不需要填充。

所以&#xff0c;VisualVM的显示结果有问首先&#xff0c;没有考虑是否开启UseCompressedOops

其次&#xff0c;没有考虑对齐填充的情况

感兴趣的同学&#xff0c;可以动手实践一下&#xff0c;加深对对象内存布局的印象。

经过这段时间对MAT和VisualVM源码的研究&#xff0c;发现MAT的功能不是强大一点点&#xff0c;建议大家以后都使用MAT对dump文件进行分析。



推荐阅读
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 流数据流和IO流的使用及应用
    本文介绍了流数据流和IO流的基本概念和用法,包括输入流、输出流、字节流、字符流、缓冲区等。同时还介绍了异常处理和常用的流类,如FileReader、FileWriter、FileInputStream、FileOutputStream、OutputStreamWriter、InputStreamReader、BufferedReader、BufferedWriter等。此外,还介绍了系统流和标准流的使用。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
天佑伈似_倥伯
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有