我知道class
类型或引用类型在堆栈内存中有引用,而值类型(如果定义为局部变量)也驻留在堆栈中。但是,我知道int
,double
等类型如何驻留在堆栈中,但不太确定自定义结构类型如何位于堆栈中。例如:
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
结构如何驻留在内存中吗?我可以想象Age
和Name
与其他变量一样,但Employee
如何将它们封装在堆栈中?一个很好的详细解释会非常好。
答案 0 :(得分:4)
当所有值类型(即结构)是局部变量或按值参数(即通常的参数类型)时,它们仅存储在堆栈 中。这包括int,bool等和自定义结构。回答“如何”这种情况只是知道内存存储一般如何工作的问题,但基本思想是它与引用类型完全相同,除了计算机使用称为“堆栈”的内存区域而不是内存区域称为“堆”。这两个领域之间的主要区别在于如何管理区域的使用。否则,它们都只是计算机内存中的位置并且工作方式相同(即指向一个指针的指针与指向另一个指针的指针相同)。
有关引用类型与值类型的更多信息,特别是为什么您不应该真正关心存储值类型的位置(特别是因为当引用类型的一部分,它们仍然存储在堆中时),请参阅此类来自Eric Lippert的已知文章: http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx
答案 1 :(得分:2)
在正常情况下,你不应该担心结构在内存中是如何布局的。 CLR决定它自己的。如果需要特定布局,可以使用StructLayout属性控制它。
您的案例中的new关键字只提供了在堆上新建类对象时使用的相同语义。
Employee employee;
employee = new Employee();
等于写作:
var employee = new Employee();
实际上,如果你不使用new运算符,它将在下一行报告:
..使用未分配的局部变量
employee
。
分配源结构的所有字段的结构变量副本,但事实并非如此,因为它只是一个初始化表达式,并且没有理由复制任何内容。 构造函数只是作用于驻留在堆栈中的新对象的字段及其字段值,就像您声明了一组类似的局部变量一样。在这种情况下,它只是使用默认值对fileds进行初始化:对于int为零,对于字符串为null。
在本声明中:
employee.Name = "Hello World";
它调用setter函数,后者又将值赋给私有字段。如果使用优化进行编译,则会内联此setter函数。
答案 2 :(得分:2)
正如其他人所说,你几乎不需要担心堆栈在内存中的实际布局,或者就此而言,是否完全使用堆栈。请记住,寄存器通常也用于实现临时存储。
抖动在堆栈上布置记录的方式取决于实现,并且可能因机器而异。要了解程序如何在机器内存中进行布局:编译,调试,进入汇编级调试,并检查堆栈寄存器周围的内存。
,请注意当您从一个语句转到另一个语句时,该内存会如何变化。