Java中对象的内存消耗是多少? [英] What is the memory consumption of an object in Java?

查看:32
本文介绍了Java中对象的内存消耗是多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

1个100个属性的对象和100个每个1个属性的对象消耗的内存空间一样吗?

Is the memory space consumed by one object with 100 attributes the same as that of 100 objects, with one attribute each?

为一个对象分配了多少内存?
添加属性时使用了多少额外空间?

How much memory is allocated for an object?
How much additional space is used when adding an attribute?

推荐答案

Mindprod 指出这不是一个直接回答的问题:

Mindprod points out that this is not a straightforward question to answer:

JVM 可以自由地在内部以任何它喜欢的方式存储数据,大端或小端,有任意数量的填充或开销,但原语必须表现得好像它们具有官方大小.
例如,JVM 或本机编译器可能决定将 boolean[] 存储在 64 位长块中,如 BitSet.它不必告诉你,只要程序给出相同的答案即可.

A JVM is free to store data any way it pleases internally, big or little endian, with any amount of padding or overhead, though primitives must behave as if they had the official sizes.
For example, the JVM or native compiler might decide to store a boolean[] in 64-bit long chunks like a BitSet. It does not have to tell you, so long as the program gives the same answers.

  • 它可能会在堆栈上分配一些临时对象.
  • 它可能会优化一些完全不存在的变量或方法调用,用常量代替它们.
  • 它可能会版本方法或循环,即编译一个方法的两个版本,每个版本都针对特定情况进行了优化,然后预先决定调用哪个版本.

当然,硬件和操作系统有多层缓存,片上缓存、SRAM 缓存、DRAM 缓存、普通 RAM 工作集和磁盘后备存储.您的数据可能会在每个缓存级别重复.所有这些复杂性意味着您只能非常粗略地预测 RAM 消耗.

Then of course the hardware and OS have multilayer caches, on chip-cache, SRAM cache, DRAM cache, ordinary RAM working set and backing store on disk. Your data may be duplicated at every cache level. All this complexity means you can only very roughly predict RAM consumption.

测量方法

您可以使用 Instrumentation.getObjectSize() 获取对象消耗的存储空间的估计值.

Measurement methods

You can use Instrumentation.getObjectSize() to obtain an estimate of the storage consumed by an object.

要可视化实际对象布局、足迹和引用,您可以使用JOL(Java 对象布局)工具.

To visualize the actual object layout, footprint, and references, you can use the JOL (Java Object Layout) tool.

在现代 64 位 JDK 中,对象具有 12 字节的标头,填充为 8 字节的倍数,因此最小对象大小为 16 字节.对于 32 位 JVM,开销为 8 字节,填充为 4 字节的倍数.(来自Dmitry Spikhalskiy 的回答Jayen 的回答,以及JavaWorld.)

In a modern 64-bit JDK, an object has a 12-byte header, padded to a multiple of 8 bytes, so the minimum object size is 16 bytes. For 32-bit JVMs, the overhead is 8 bytes, padded to a multiple of 4 bytes. (From Dmitry Spikhalskiy's answer, Jayen's answer, and JavaWorld.)

通常,引用在 32 位平台或 64 位平台上为 4 个字节,最高可达 -Xmx32G;和 32Gb 以上的 8 个字节 (-Xmx32G).(参见压缩对象引用.)

Typically, references are 4 bytes on 32bit platforms or on 64bit platforms up to -Xmx32G; and 8 bytes above 32Gb (-Xmx32G). (See compressed object references.)

因此,64 位 JVM 通常需要多 30-50% 的堆空间.(我应该使用 32 位还是 64 位 JVM?,2012,JDK 1.7)

As a result, a 64-bit JVM would typically require 30-50% more heap space. (Should I use a 32- or a 64-bit JVM?, 2012, JDK 1.7)

盒装包装器与原始类型相比有开销(来自 JavaWorld):

Boxed wrappers have overhead compared to primitive types (from JavaWorld):

  • Integer:16 字节的结果比我预期的要差一点,因为 int 值只能容纳 4额外的字节.与将值存储为原始类型相比,使用 Integer 花费了 300% 的内存开销

  • Integer: The 16-byte result is a little worse than I expected because an int value can fit into just 4 extra bytes. Using an Integer costs me a 300 percent memory overhead compared to when I can store the value as a primitive type

Long:同样为 16 字节:显然,堆上的实际对象大小取决于特定 JVM 实现为特定的 CPU 类型.看起来 Long 是 8 字节的对象开销,加上实际长值的 8 字节.相比之下,Integer 有一个未使用的 4 字节空洞,很可能是因为我使用的 JVM 在 8 字节字边界上强制对象对齐.

Long: 16 bytes also: Clearly, actual object size on the heap is subject to low-level memory alignment done by a particular JVM implementation for a particular CPU type. It looks like a Long is 8 bytes of Object overhead, plus 8 bytes more for the actual long value. In contrast, Integer had an unused 4-byte hole, most likely because the JVM I use forces object alignment on an 8-byte word boundary.

其他容器也很昂贵:

  • 多维数组:它提供了另一个惊喜.
    开发人员通常在数值和科学计算中使用像 int[dim1][dim2] 这样的结构.

  • Multidimensional arrays: it offers another surprise.
    Developers commonly employ constructs like int[dim1][dim2] in numerical and scientific computing.

int[dim1][dim2] 数组实例中,每个嵌套的 int[dim2] 数组本身就是一个 Object.每个都会增加通常的 16 字节数组开销.当我不需要三角形或参差不齐的数组时,这表示纯粹的开销.当数组维度差异很大时,影响会增加.

In an int[dim1][dim2] array instance, every nested int[dim2] array is an Object in its own right. Each adds the usual 16-byte array overhead. When I don't need a triangular or ragged array, that represents pure overhead. The impact grows when array dimensions greatly differ.

例如,一个 int[128][2] 实例占用 3,600 字节.与 int[256] 实例使用的 1,040 字节(具有相同容量)相比,3,600 字节代表 246% 的开销.在 byte[256][1] 的极端情况下,开销因子几乎是 19!将其与相同语法不增加任何存储开销的 C/C++ 情况进行比较.

For example, a int[128][2] instance takes 3,600 bytes. Compared to the 1,040 bytes an int[256] instance uses (which has the same capacity), 3,600 bytes represent a 246 percent overhead. In the extreme case of byte[256][1], the overhead factor is almost 19! Compare that to the C/C++ situation in which the same syntax does not add any storage overhead.

String:String 的内存增长跟踪其内部字符数组的增长.但是,String 类又增加了 24 个字节的开销.

String: a String's memory growth tracks its internal char array's growth. However, the String class adds another 24 bytes of overhead.

对于大小为 10 个字符或更少的非空 String,相对于有用负载(每个字符 2 个字节加上长度为 4 个字节)的额外开销成本在 100% 到 400% 之间.

For a nonempty String of size 10 characters or less, the added overhead cost relative to useful payload (2 bytes for each char plus 4 bytes for the length), ranges from 100 to 400 percent.

对齐

考虑一下 示例对象:

class X {                      // 8 bytes for reference to the class definition
   int a;                      // 4 bytes
   byte b;                     // 1 byte
   Integer c = new Integer();  // 4 bytes for a reference
}

一个简单的总和表明 X 的实例将使用 17 个字节.但是,由于对齐(也称为填充),JVM 以 8 个字节的倍数分配内存,因此分配 24 个字节而不是 17 个字节.

A naïve sum would suggest that an instance of X would use 17 bytes. However, due to alignment (also called padding), the JVM allocates the memory in multiples of 8 bytes, so instead of 17 bytes it would allocate 24 bytes.

这篇关于Java中对象的内存消耗是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆