1

可能重复:
内存中字节的大小 - Java

我在一篇文章中读到了这一点。我只是按原样粘贴:

  • 该类至少占用 8 个字节。所以,如果你说**new Object();**你将在堆上分配 8 个字节。
  • 每个数据成员占用 4 个字节,除了 long 和 double 占用 8 个字节。即使数据成员是一个字节,它仍然会占用4个字节!此外,使用的内存量以 8 字节块的形式增加。因此,如果您有一个包含一个字节的类,它将占用该类的 8 个字节和用于数据的 8 个字节,总共 16 个字节(呻吟!)。

真的Java字节分配/占用4个字节吗?空类占用 8 个字节?它在这里也令人困惑。

4

3 回答 3

5

由于 Java 规范不要求使用内存,这取决于您使用的 JVM 实现。

当然,在所有 JVM 实现中都会有每个对象的开销(例如,为了实现运行时类型检查)。JVM 可能会选择内存对齐字段(在某些平台上,这会在访问字段时显着加快速度)。

但是,如果数组成员为内存对齐而填充,并且可以确认(至少在 Windows 的 oracle vm 上)一个 boolean[] 每个元素占用一个字节,我会感到非常惊讶。

此外,值得注意的是,如果您碰巧处理了一个适当大的堆,则引用类型字段的大小可以是 8 个字节。

总结:如果您真的想知道,请测量目标 JVM 上的内存消耗。

编辑:出于好奇,我写了一个小的(不准确的)基准:

class FourBytes {
    byte a,b,c,d;
}

public class Test {

    long usedBefore = used();

    long used() {
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }

    public void before() {
        System.gc();
        usedBefore = used();
    }

    public void after(String text) {
        long usedAfter = used();
        System.out.println(text + "\t" + new BigDecimal(usedAfter - usedBefore).movePointLeft(6) + " bytes");
        before();
    }

    {
        int max = 1000000;
        before();
        boolean[] bools = new boolean[max];
        after("boolean in array");

        char[] chars = new char[max];
        after("char in array   ");

        Object[] objects = new Object[max];
        after("reference type in array");

        for (int i = 0; i < max; i++) {
            objects[i] = new Object();
        }
        after("Object instance  ");

        Byte[] bytes = new Byte[max];
        before();
        for (int i = 0; i < max; i++) {
            bytes[i] = new Byte((byte) i);
        }
        after("Byte instance    ");


        Integer[] integers = new Integer[max];
        before();
        for (int i = 0; i < max; i++) {
            integers[i] = new Integer(i);
        }
        after("Integer instance");

        FourBytes[] fbs = new FourBytes[max];
        before();
        for (int i = 0; i < max; i++) {
            fbs[i] = new FourBytes();
        }
        after("FourBytes instance");

    }

    public static void main(String[] args) throws Exception {
        new Test();
    }
}

java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) Client VM (build 22.0-b10, mixed mode, sharing)

它打印:

boolean in array    1.183624 bytes
char in array       2.091768 bytes
reference type in array 4.091768 bytes
Object instance     8.023664 bytes
Byte instance       16.133408 bytes
Integer instance    16.147312 bytes
FourBytes instance  16.142568 bytes
于 2012-11-09T17:34:37.137 回答
3

该类至少占用 8 个字节。所以,如果你说new Object(); 您将在堆上分配 8 个字节。

在 OpenJDK/HotSpot JVM 中,它将在 32 位 JVM 上使用 8 个字节,在 64 位 JVM 上使用 16 个字节。

每个数据成员占用 4 个字节,除了 long 和 double 占用 8 个字节。

最小大小是 1 个字节而不是 4 个字节。即使在 64 位 JVM 上,引用通常也使用 4 个字节。

即使数据成员是一个字节,它仍然会占用4个字节!

这是一个新的想法。我不知道你是怎么得出这个结论的。

此外,使用的内存量以 8 字节块的形式增加。

从技术上讲,它与 8 字节边界对齐。

因此,如果您有一个包含一个字节的类,则该类将占用 8 个字节

在 32 位或 64 位 JVM 中,标头将占用 8 或 12 个字节,加上该字节的 1 个字节,并向上舍入到下一个 8 字节边界。

和 8 个字节的数据,总共 16 个字节(呻吟!)。

确实,但是每个可能的 Byte 对象都被缓存和自动装箱,你没有理由这样做。你永远不需要显式甚至隐式地创建一个字节。

Byte b = new Byte((byte) 1); // bad idea.
Byte b = 1; // simpler and more efficient
byte b = 1; // the most efficient option.
于 2012-11-09T18:12:10.460 回答
2

这是错误的,至少对于 HotSpot JVM 而言。在那里,类中的原始字节字段将占用一个字节,但确实,类实例的大小从 8 个字节开始,并且字段被分组为每个占用 8 个字节的块——例如,您可以'不要跨 8 字节边界分割字段。

参见例如http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html

于 2012-11-09T17:26:41.083 回答