静态字段在内部究竟是如何工作的?

2022-08-30 09:05:04

假设你有一堂课,

class Foo
{
    public static bar;
}

当你说:

new Foo();

我可以想象,在内存中,为这个对象保留了一个空间。

...当你再次说:

new Foo(); 

...好吧,现在你有另一个空间可用于对象。

但是,静态场究竟位于何处?

我真正想学习的是:

对对象的引用如何引用它们所引用的对象的相同字段?


答案 1

虽然类型系统的确切细节取决于实现,但让我更详细地介绍一下,而不仅仅是说它取决于,你不应该关心。我将根据 Jeffrey Richter 的《CLR via C#》一书和 Hanu Kommalapati 等人的文章《请参阅 CLR 如何创建运行时对象》(原始 MSDN 2005 年 5 月刊)描述它在 Microsoft 的实现 (.NET) 中大致的工作方式。


假设您有一个班级:

class Foo
{
    // Instance fields
    string myBar = "Foobar";
    int myNum;

    // Static fields
    static string bar = "Foobar";
    static int num;
}

Foo myFoo = new Foo();
Type typeOfFoo = typeof(Foo);

实例字段位于何处?

每当您说 ,将为对象实例分配和初始化空间,并调用构造函数。此实例在下图中显示为 Foo 的实例。例如,instance 仅包含类的实例字段(在本例中为 和 ),对于堆上分配的对象,运行时使用两个额外的字段 ( 和 )。类型句柄是指向描述实例类型的对象的指针,在本例中为 Foo 类型new Foo()myBarmyNumSync block indexType handleType

当您再次说时,将分配新空间,该空间将再次包含该类型的实例字段的空间。如您所见,实例字段与对象实例相关联。new Foo()

运行时将每个实例字段置于从对象数据开始的固定偏移量。例如,可能位于偏移量 +4 处。实例字段的地址只是对象的地址加上字段的偏移量。myBar

静态字段位于何处?

C# 和 Java 中的静态字段不与任何对象实例相关联,而是与类型相关联。类、结构和枚举是类型的示例。只有一次(每个类型)分配一些空间来保存静态字段的值。在描述类型的结构中为静态字段分配空间是有意义的,因为每个类型也只有一个对象。这是 C# 和 Java 采用的方法。TypeType

对象1 是在运行时加载类型时创建的。此结构包含运行时能够分配新实例、调用方法和执行强制转换等所需的所有信息。它还包含静态字段的空间,在本例中为 和 。Typebarnum

运行时已将每个静态字段放在距类型数据开头的某个偏移处。这对于每种类型都是不同的。例如,可能位于偏移量 +64 处。静态字段的地址是对象的地址加上字段的偏移量。该类型是静态已知的。barType

Displays some object structures, and their relationships.

1)在Microsoft .NET中,多种不同的结构描述了一种类型,例如MethodTableEEClass结构。


答案 2

这完全取决于所讨论的实现。对于 C# 和 Java,允许运行时确定在何处存储变量的内存。对于 C 和大多数编译语言,编译器会做出此决定。

话虽如此,在实践中,这并不重要。它的用法由规范决定,因此您可以自由使用知道行为的变量将得到保证。


推荐