Java中对象的内存消耗是多少?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/258120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:07:28  来源:igfitidea点击:

What is the memory consumption of an object in Java?

javamemoryfootprint

提问by

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

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

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

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

回答by Mendelt

No, registering an object takes a bit of memory too. 100 objects with 1 attribute will take up more memory.

不,注册一个对象也需要一些内存。具有 1 个属性的 100 个对象将占用更多内存。

回答by Burkhard

no, 100 small objects needs more information (memory) than one big.

不,100 个小物体比一个大物体需要更多的信息(内存)。

回答by Jon Skeet

Each object has a certain overhead for its associated monitor and type information, as well as the fields themselves. Beyond that, fields can be laid out pretty much however the JVM sees fit (I believe) - but as shown in another answer, at least someJVMs will pack fairly tightly. Consider a class like this:

每个对象对其关联的监视器和类型信息以及字段本身都有一定的开销。除此之外,几乎可以按照 JVM 认为合适的方式布置字段(我相信) - 但如另一个答案所示,至少一些JVM 会打包得相当紧。考虑这样一个类:

public class SingleByte
{
    private byte b;
}

vs

对比

public class OneHundredBytes
{
    private byte b00, b01, ..., b99;
}

On a 32-bit JVM, I'd expect 100 instances of SingleByteto take 1200 bytes (8 bytes of overhead + 4 bytes for the field due to padding/alignment). I'd expect one instance of OneHundredBytesto take 108 bytes - the overhead, and then 100 bytes, packed. It can certainly vary by JVM though - one implementation may decide not to pack the fields in OneHundredBytes, leading to it taking 408 bytes (= 8 bytes overhead + 4 * 100 aligned/padded bytes). On a 64 bit JVM the overhead may well be bigger too (not sure).

在 32 位 JVM 上,我希望 100 个实例SingleByte占用 1200 字节(由于填充/对齐,8 字节的开销 + 4 字节的字段)。我希望一个实例OneHundredBytes占用 108 字节 - 开销,然后是 100 字节,打包。不过,它肯定会因 JVM 的不同而有所不同——一种实现可能决定不将字段打包到 中OneHundredBytes,导致它占用 408 字节(= 8 字节开销 + 4 * 100 对齐/填充字节)。在 64 位 JVM 上,开销也可能更大(不确定)。

EDIT: See the comment below; apparently HotSpot pads to 8 byte boundaries instead of 32, so each instance of SingleBytewould take 16 bytes.

编辑:请参阅下面的评论;显然 HotSpot 填充到 8 个字节的边界而不是 32 个,因此每个实例SingleByte将占用 16 个字节。

Either way, the "single large object" will be at least as efficient as multiple small objects - for simple cases like this.

无论哪种方式,“单个大对象”至少与多个小对象一样有效 - 对于像这样的简单情况。

回答by VonC

Mindprodpoints out that this is not a straightforward question to answer:

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

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.

  • It might allocate some temporary Objects on the stack.
  • It may optimize some variables or method calls totally out of existence replacing them with constants.
  • It might version methods or loops, i.e. compile two versions of a method, each optimized for a certain situation, then decide up front which one to call.

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.

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

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

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

Measurement methods

测量方法

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

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

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

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

Object headers and Object references

对象头和对象引用

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.)

在现代 64 位 JDK 中,对象具有 12 字节的标头,填充为 8 字节的倍数,因此最小对象大小为 16 字节。对于 32 位 JVM,开销为 8 字节,填充为 4 字节的倍数。 (从梅德Spikhalskiy的回答Jayen的回答,和JavaWorld的。)

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.)

通常,引用在 32 位平台或 64 位平台上为 4 个字节,最多为-Xmx32G; 和 32Gb ( -Xmx32G)以上的 8 个字节。 (请参阅压缩对象引用。)

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)

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

Boxed types, arrays, and strings

盒装类型、数组和字符串

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

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

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

  • 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 Longis 8 bytes of Object overhead, plus 8 bytes more for the actual long value. In contrast, Integerhad an unused 4-byte hole, most likely because the JVM I use forces object alignment on an 8-byte word boundary.

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

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

Other containers are costly too:

其他容器也很昂贵:

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

    In an int[dim1][dim2]array instance, every nested int[dim2]array is an Objectin 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.

    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: a String's memory growth tracks its internal char array's growth. However, the Stringclass adds another 24 bytes of overhead.

    For a nonempty Stringof 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.

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

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

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

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

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

Alignment

结盟

Consider this example object:

考虑这个示例对象

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
}

A na?ve sum would suggest that an instance of Xwould 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.

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

回答by Matt Passell

I've gotten very good results from the java.lang.instrument.Instrumentationapproach mentioned in another answer. For good examples of its use, see the entry, Instrumentation Memory Counterfrom the JavaSpecialists' Newsletter and the java.sizeOflibrary on SourceForge.

我从另一个答案中提到的java.lang.instrument.Instrumentation方法中获得了非常好的结果。有关其使用的良好示例,请参阅JavaSpecialists' Newsletter 中的条目Instrumentation Memory Counter和SourceForge 上的java.sizeOf库。

回答by kohlerm

The rules about how much memory is consumed depend on the JVM implementation and the CPU architecture (32 bit versus 64 bit for example).

有关消耗多少内存的规则取决于 JVM 实现和 CPU 架构(例如 32 位与 64 位)。

For the detailed rules for the SUN JVM check my old blog

SUN JVM的详细规则查看我的旧博客

Regards, Markus

问候, 马库斯

回答by Neil Coffey

In case it's useful to anyone, you can download from my web site a small Java agent for querying the memory usage of an object. It'll let you query "deep" memory usage as well.

如果它对任何人有用,您可以从我的网站下载一个用于查询对象内存使用情况的小型Java 代理。它还可以让您查询“深度”内存使用情况。

回答by nazar_art

The total used / free memory of an program can be obtained in the program via

程序的总已用/空闲内存可以通过以下方式在程序中获得

java.lang.Runtime.getRuntime();

The runtime has several method which relates to the memory. The following coding example demonstrate its usage.

运行时有几种与内存相关的方法。下面的编码示例演示了它的用法。

package test;

 import java.util.ArrayList;
 import java.util.List;

 public class PerformanceTest {
     private static final long MEGABYTE = 1024L * 1024L;

     public static long bytesToMegabytes(long bytes) {
         return bytes / MEGABYTE;
     }

     public static void main(String[] args) {
         // I assume you will know how to create a object Person yourself...
         List < Person > list = new ArrayList < Person > ();
         for (int i = 0; i <= 100000; i++) {
             list.add(new Person("Jim", "Knopf"));
         }
         // Get the Java runtime
         Runtime runtime = Runtime.getRuntime();
         // Run the garbage collector
         runtime.gc();
         // Calculate the used memory
         long memory = runtime.totalMemory() - runtime.freeMemory();
         System.out.println("Used memory is bytes: " + memory);
         System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
     }
 }

回答by Nikhil Agrawal

The question will be a very broad one.

这个问题将是一个非常广泛的问题。

It depends on the class variable or you may call as states memory usage in java.

这取决于类变量,或者您可以在 java 中调用作为状态内存使用情况。

It also has some additional memory requirement for headers and referencing.

它还对标头和引用有一些额外的内存要求。

The heap memory used by a Java object includes

Java 对象使用的堆内存包括

  • memory for primitive fields, according to their size (see below for Sizes of primitive types);

  • memory for reference fields (4 bytes each);

  • an object header, consisting of a few bytes of "housekeeping" information;

  • 原始字段的内存,根据它们的大小(参见下面的原始类型的大小);

  • 用于参考字段的内存(每个 4 个字节);

  • 一个对象头,由几个字节的“内务处理”信息组成;

Objects in java also requires some "housekeeping" information, such as recording an object's class, ID and status flags such as whether the object is currently reachable, currently synchronization-locked etc.

Java 中的对象还需要一些“内务处理”信息,例如记录对象的类、ID 和状态标志,例如对象当前是否可达、当前是否同步锁定等。

Java object header size varies on 32 and 64 bit jvm.

Java 对象标头大小在 32 位和 64 位 jvm 上有所不同。

Although these are the main memory consumers jvm also requires additional fields sometimes like for alignment of the code e.t.c.

虽然这些是主要的内存消费者,但 jvm 有时也需要额外的字段,例如代码对齐等

Sizes of primitive types

原始类型的大小

boolean & byte-- 1

布尔值和字节-- 1

char & short-- 2

字符和短- 2

int & float-- 4

整数和浮点数-- 4

long & double-- 8

长双倍-- 8

回答by Arun

It appears that every object has an overhead of 16 bytes on 32-bit systems (and 24-byte on 64-bit systems).

似乎每个对象在 32 位系统上都有 16 字节的开销(在 64 位系统上是 24 字节)。

http://algs4.cs.princeton.edu/14analysis/is a good source of information. One example among many good ones is the following.

http://algs4.cs.princeton.edu/14analysis/是一个很好的信息来源。以下是众多优秀示例中的一个示例。

enter image description here

在此处输入图片说明

http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdfis also very informative, for example:

http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf也非常有用,例如:

enter image description here

在此处输入图片说明