一个拥有100个属性的对象所消耗的内存空间是否与100个对象各有一个属性所消耗的内存空间相同?

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


当前回答

每个对象对于其关联的监视器和类型信息以及字段本身都有一定的开销。除此之外,字段可以按照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 SingleByte to take 1200 bytes (8 bytes of overhead + 4 bytes for the field due to padding/alignment). I'd expect one instance of OneHundredBytes to 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).

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

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

其他回答

这取决于架构/jdk。对于现代JDK和64位体系结构,一个对象有12字节的头部和8字节的填充-因此最小对象大小是16字节。您可以使用一个名为Java对象布局的工具来确定大小,并获得关于任何实体的对象布局和内部结构的详细信息,或者通过类引用来猜测这些信息。在我的环境中输出Integer的例子:

Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0    12       (object header)                N/A
     12     4   int Integer.value                  N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

因此,对于Integer,实例大小为16字节,因为4字节int压缩在头文件之后和填充边界之前。

代码示例:

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;

public static void main(String[] args) {
    System.out.println(VMSupport.vmDetails());
    System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}

如果你使用maven,得到JOL:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.3.2</version>
</dependency>

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

程序的总已用/空闲内存可以在程序中通过

java.lang.Runtime.getRuntime();

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

 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 an object Person yourself...
         List <Person> list = new ArrayList <Person> ();
         for (int i = 0; i <= 100_000; 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));
     }
 }

每个对象对于其关联的监视器和类型信息以及字段本身都有一定的开销。除此之外,字段可以按照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 SingleByte to take 1200 bytes (8 bytes of overhead + 4 bytes for the field due to padding/alignment). I'd expect one instance of OneHundredBytes to 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).

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

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

我已经从另一个答案中提到的java.lang.instrument.Instrumentation方法中获得了非常好的结果。有关它的使用示例,请参阅java专家通讯和java。SourceForge上的sizeOf库。