内存中的自定义结构类型

本文关键字:结构 类型 自定义 内存 | 更新日期: 2023-09-27 18:27:22

我知道class类型或引用类型在堆栈内存中有一个引用,而值类型如果定义为局部变量,也会驻留在堆栈中。然而,我知道intdouble等类型是如何驻留在堆栈中的,但不太确定自定义结构类型是如何位于堆栈中的。例如:

public struct Employee
{
   public int Age {get;set;}
   public string Name {get;set;}
}
static void Main(params string[] args)
{
   Employee employee; // How does it look like in stack at the moment of declaration?
   employee = new Employee(); // And during this line?
   employee.Name = "Hello World"; // And during this statement?
}

你能解释一下employee结构体是如何驻留在内存中的吗?我可以想象AgeName的位置和其他变量一样,但Employee是如何将它们封装在堆栈中的?一个很好的详细解释将是非常好的。

内存中的自定义结构类型

所有值类型(即struct)仅当它们是局部变量或按值参数(即通常类型的参数)时才存储在堆栈中。这包括int、bool等以及自定义结构。回答"如何"发生这种情况只是了解内存存储通常是如何工作的,但基本思想是,它的工作原理与引用类型完全相同,只是计算机使用称为"堆栈"的内存区域,而不是称为"堆"的内存区域。这两个领域之间的主要区别只是如何管理这些领域的使用。否则,它们都只是计算机内存中的位置,工作方式相同(即,指向其中一个的指针与指向另一个的指示器工作方式相同)。

有关引用类型与值类型的更多信息,特别是为什么你不应该真正关心值类型存储在哪里(尤其是当引用类型是一部分时,它们仍然存储在堆中),请参阅Eric Lippert的这篇著名文章:http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

正如其他人所说,您几乎不需要担心堆栈在内存中的实际布局,也不需要担心是否使用了堆栈。请记住,寄存器通常也用于实现临时存储。

抖动在堆栈上布置记录的方式取决于实现,并且可能因机器而异。要了解程序在机器内存中的布局:编译、调试程序,进入汇编级调试,并检查堆栈寄存器周围的内存。当你从一个语句走到另一个语句时,观察记忆是如何变化的,很快你就会明白。

在正常情况下,您不应该担心结构在内存中的布局。CLR自己决定。如果需要特定布局,可以使用StructLayout属性对其进行控制。

在您的案例中,new关键字只是提供了与在堆上新建类对象时使用的语义相同的语义。

Employee employee;
employee = new Employee();

等于写入:

var employee = new Employee();

事实上,如果你不使用新的操作员,它将在下一行报告:

使用未分配的局部变量employee

结构变量的赋值复制了源结构的所有字段,但事实并非如此,因为它只是一个初始化表达式,还没有理由复制任何内容。构造函数只对驻留在堆栈中的新对象的字段及其字段值进行操作,就像您声明了一组类似的局部变量一样。在这种情况下,它只是用默认值初始化文件:零表示int,null表示字符串。

在这份声明中:

employee.Name = "Hello World";

它调用一个setter函数,该函数又将值分配给一个私有字段。如果使用优化进行编译,则此setter函数将内联。