C# 中结构体中的引用类型。

6

我正在学习 C# 中的类型值,并了解到它们不像普通引用类型那样在堆上分配。那么,一个带有引用类型的结构体如何分配内存呢?

例如:

struct simple {
    public Employee e;
    public bool topEmployee;
    public void printSomething()
    {
        Console.WriteLine("Progress " + e.GetProgressReport());
        Console.WriteLine("TopEmployee " + topEmployee);
    }
};

Employee 是一个类。当初始化时,e 会分配到堆上吗?这是否违背了使用结构体的初衷?

3个回答

9

类型的“种类”(值/引用)与实例分配方式关系不大。它与生命周期有关,而且有更多的分配方式,不仅仅是“堆栈”。请阅读关于值类型的真相

但就你的问题而言:结构体成员类型不会影响结构体实例的分配方式,因为它们不会影响对象的生命周期。顺便说一下,对于类也是如此。

成员e将成为值类型对象的一部分,并在可能的位置进行分配。该成员是一个引用,因此任何实际的Employee对象e所指向的对象都将在其他地方分配1。虽然听起来像是特殊规则,但这并不是特殊规则;局部变量、类成员和数组项的行为方式相同。这并没有破坏值类型的优点,而是保持了值类型和引用类型的优点。值类型实例仍然是单独的值,而不是别名,它们仍然具有更简单和更短的生命周期,可以更轻松地进行更好的分配选择。引用类型实例仍然是共享的,并且(潜在地)具有长寿命。

1 至少在概念上和当前的实现中;在非常简单的情况下,优化(逃逸分析+分配下沉)可能会合并这些分配,但是我所知道的任何CLR都没有这样做。


6
结构体内存是“内联”分配的。类内存在堆上分配,而引用(指针)则是“内联”分配的。
如果你在程序中看到一个名为C的类变量,那么该变量的存储空间将等同于一个指针(比如4个字节),而类的实际存储空间将在堆上。
但是,如果你在程序中看到一个名为S的结构体变量,则该变量的存储空间仅仅是在声明点处的变量大小。没有为它分配堆存储空间。
如果C包含S,则S将位于C的堆存储空间中。
如果S包含C,则对C的引用将位于S的存储空间中,而C的存储空间则在堆上。这就是关于simple和e的问题的答案。
因此,结构体存储实际上可以在静态内存中、堆栈上或类内部的堆上。而类内存永远在堆上。

0

引用变量'e'将被分配在结构体所分配的位置(例如,未装箱结构类型的局部变量可能会进入堆栈)。指向Employee实例的'e'将在堆上分配。这可能因.NET实现而异,但对于所有当前实现来说,这很可能是真实的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接