14

我有这门课:

public class Stack {

   private class Node {
       String item;
       Node next;
   }
   // some other methods here

}

在我的书中,作者说每个堆栈节点的大小是 40 字节,包括:

16 bytes (object overhead)
8 bytes (inner class extra overhead)
8 bytes (references to string)
8 bytes (references to node)
----------------------------------------------
40 bytes per stack node

我知道最后两件事是指对字符串和节点的引用的大小。但我不知道object overheadandinner class extra overhead对应什么。你能解释一下吗?

4

8 回答 8

6

对象开销

每个对象都有一个通常为 8-12 字节长的标头。每个对象也是 8 字节对齐的,一个简单的估计是你说它大约 16 字节长。

内部类额外开销

由于您的内部类不是静态的,因此它具有对外部类的引用。

如果这是一个匿名内部类,您可能拥有任意数量的最终变量的副本(在匿名类代码中使用的任何变量)

8 个字节(内部类额外开销) 8 个字节(对字符串的引用) 8 个字节(对节点的引用)

大多数 JVM 使用 32 位引用,因此大小为 4 个字节。即使是堆高达 32 GB 的 64 位 JVM 也可以使用 32 位引用。

于 2012-08-30T08:54:29.613 回答
3

首先:您引用的所有具体数字都非常依赖于实现,并且根据您使用的 JVM 可能会有很大差异。

然而,大多数 JVM 将具有相似的值(例如,大多数 JVM 使用对象标头)。

对象标头包含 JVM 跟踪对象所需的“簿记”信息。例如,它通常会包含指示对象确切类型的内容。

您所说的“内部类额外开销”可能是指非静态内部类的每个实例都“绑定”到外部类的实例这一事实。您可以将其视为如下所示的隐式字段:private final Stack Stack_this. 实际上,您可以通过引用Stack.this内部代码来实际使用该值Node。该隐式字段将占用与普通引用变量相同的内存量(通常为 4 或 8 个字节,具体取决于您的体系结构/JVM)。

于 2012-08-30T08:54:36.410 回答
2

在这里你可以找到答案: Java中一个对象的内存开销是多少?

这里有一个更详细的答案:

Java 中的对象内存使用: http ://www.javamex.com/tutorials/memory/object_memory_usage.shtml

Java 堆上的对象实例不只是为它们的实际字段占用内存。不可避免地,它们还需要一些“管理”信息,例如记录对象的类、ID 和状态标志,例如对象当前是否可访问、当前是否已同步锁定等。

于 2012-08-30T08:52:26.367 回答
2

内部类对外部类有一个隐式引用,就好像它有一个Stack outer在构造函数中初始化的对象。该引用消耗了额外的 8 个字节,它允许您Stack.this在内部类中使用它。这是一个示例片段:

public class Stack {
    String item;   // intentionally named the same as the one in the inner class

    private class Node {
        String item; // hides the field in the outer class!
        Node next;

        void doSomething() {
            this.item = null;
            Stack.this.item = null; // << note the reference to the outer instance
        }
    }
}

请注意,static内部类不会产生这种开销,因为它没有指向外部对象的指针。

于 2012-08-30T08:53:53.150 回答
2

内部类的实例将按照正常规则进行垃圾收集(即当它们不再被引用时)。但是,内部类的每个实例都包含对其外部类的父实例的隐藏引用。这意味着如果有任何对内部类实例的实时引用,它们将阻止外部类的关联实例被垃圾收集。但它只在那个方向起作用,而不是相反。

于 2016-12-08T16:42:41.337 回答
1

任何特定对象的确切大小都没有在任何 Java 平台规范中具体定义

与对象相关的开销量未定义,但通常为 8 个字节。

请参阅此处了解更多信息

于 2012-08-30T08:53:55.790 回答
1

首先,您的对象引用值假定 64 位 JVM,在 32 位 JVM 上,引用使用 4 个字节。

对象开销是对象的标头,其中包含有关对象的信息,由 JVM 使用,通常为 16 个字节。

内部类的开销是由于内部类持有对包含对象(Stack 实例)的引用。

于 2012-08-30T08:53:59.910 回答
0

我仍然不明白“每个堆栈节点 40 个字节”是什么意思。你知道当我创建一个新的 Node 实例时,我并没有创建一个新的 Stack 实例。创建新节点实例时如何考虑 16 字节(对象开销)?我也在关注算法,我在这里很困惑。

于 2013-02-19T03:18:31.800 回答