首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何计算Java数组的内存大小?

如何计算Java数组的内存大小?
EN

Stack Overflow用户
提问于 2018-05-24 06:44:17
回答 2查看 1.3K关注 0票数 1

我知道如何通过添加三个部分来计算Java对象的内存大小:头+属性+引用。

我也知道Java数组也是一个对象。

但是当我读到“理解JVM高级特性和最佳实践,第二版”时,它说Java数组的头由三个部分组成:标记word、类指针和数组长度。

在Hotspot 64位JVM中,它总是24字节。

但是在32位JVM中,如何计算Java数组的内存大小?

我希望你们能给我一些Java代码示例,向我展示如何计算对象的内存大小,而不是仅限于数组对象。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-24 12:18:36

实际的对象大小是特定于实现的,甚至不要求对象的所需大小在其生存期内保持不变。

一篇关于wiki.openjdk.java.net的文章声明:

对象标头布局 对象标头由本机大小的标记字、klass字、32位长字(如果对象是数组)、32位间隙(如果对齐规则需要)、以及零或多个实例字段、数组元素或元数据字段组成。(有趣的问题: Klass元对象包含紧跟在klass单词之后的C++ vtable。) 如果存在gap字段,则通常可用于存储实例字段。 如果UseCompressedOops是假的(在ILP32系统中总是这样),则标记和klass都是本地机器单词。对于数组,间隙总是存在于LP64系统上,而只存在于ILP32系统中具有64位元素的数组上。 如果UseCompressedOops为真,则klass为32位。非数组在klass之后有一个间隙字段,而数组在klass之后存储长度字段。

对于对象的大小计算“头+属性+引用”是不正确的。首先,对对象的引用不是引用对象大小的一部分。可以有任意数量的对同一对象的引用,但这些引用根本不必在堆内存或RAM中,因为优化的代码可能纯粹通过CPU寄存器访问对象。

此外,正如上面引号中所暗示的那样,有一些对齐规则使得字段所需内存的计算变得非常重要。如果存在适合于实例字段的字段,则头中可能会出现一个空白,用于存储实例字段。虽然同一类的字段可能被安排为最小化填充,但子类必须与超类的布局共存,可能会向其添加更多字段,并且只有在具有拟合类型字段的情况下才能填补空白,否则,由于类层次结构的原因,可能会有更多的空白。

对于数组,您可以从引用的文章中派生出32位HotSpot表示使用12字节的头,除非类型是long[]double[],在这种情况下为16字节。

对于64位实现,UseCompressedOops选项(默认情况下是打开的)允许将64位标记字与32位klass和32位长度组合为16字节的头。只有当UseCompressedOops关闭时,报头才会是24个字节。

票数 2
EN

Stack Overflow用户

发布于 2018-05-24 11:45:26

您可以使用由全能的Aleksey编写的JOL框架进行测试。

使用它实际上非常容易,首先让我们定义您所关心的布局:

代码语言:javascript
复制
Layouter layout32Bits =  new HotSpotLayouter(new X86_32_DataModel());
Layouter layout64Bits = new HotSpotLayouter(new X86_64_DataModel());
Layouter layout64BitsComp = new HotSpotLayouter(new X86_64_COOPS_DataModel());

然后,让我们定义一个数组并查看结果:

代码语言:javascript
复制
int [] ints = new int[1];
System.out.println(ClassLayout.parseInstance(ints, layout32Bits).toPrintable());
System.out.println(ClassLayout.parseInstance(ints, layout64Bits).toPrintable());
System.out.println(ClassLayout.parseInstance(ints, layout64BitsComp).toPrintable());

让我们一次跑一次。对于32bits VM

代码语言:javascript
复制
  [I object internals:
  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
  0     4        (object header)                           09 00 00 00 (00001001 00000000 00000000 00000000) (9)
  4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
  8     4        (object header)                           10 0b 40 29 (00010000 00001011 01000000 00101001) (692062992)
 12    40    int [I.<elements>                             N/A
 52    12        (loss due to the next object alignment)
 Instance size: 64 bytes
 Space losses: 0 bytes internal + 12 bytes external = 12 bytes total

因此,您获得了头部的12 bytes,(两个标头的4+4,加上数组大小的4,它是一个int);然后得到数组将容纳的10个it的40字节。

其次,我不太确定我是否理解。到目前为止,我们有52字节,对象在8 bytes上对齐,这意味着这52个值应该四舍五入到56 bytes,以使其对齐到8。

相反,它说的是12 bytes loss due to the next object alignment。我只能猜测可能有两件事,请先阅读这里的评论可能有些领域只是为了内部的目的

不打算在这里显示其余的示例输出(您也可以这样做),我将问一个后续的问题,事情是不清楚的事情,我不清楚的填充很快。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50502663

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档