这些对象是堆栈上还是堆上的引用?

如果有人能告诉我我是否理解,我会很感激:

class X { A a1=new A(); // reference on the stack, object value on the heap a1.VarA=5; // on the stack - value type A a2=a1; // reference on the stack, object value on the heap a2.VarA=10; // on the stack - value type } 

另外, a1a2引用都在堆栈上,而它们的“对象”值在堆上。 但是VarAvariables呢,还是纯粹的值types呢?

 class A { int VarA; } 

您正在询问有关实施细节的问题,所以答案将取决于具体实施。 让我们考虑一下你的程序实际编译的版本:

 class A { public int VarA; } class X { static void Main(string[] args) { A a1 = new A(); a1.VarA = 5; A a2 = a1; a2.VarA = 10; } } 

这里是在debugging模式下运行C#4.0的微软CLR 4.0上发生的事情。

此时,堆栈帧指针已被复制到寄存器ebp:

这里我们为新的对象分配堆内存。

 A a1 = new A(); mov ecx,382518h call FFE6FD30 

这将返回一个对eax中的堆对象的引用。 我们将参考存储在堆栈槽ebp-48中,这是一个与任何名称不相关的临时槽。 请记住,a1尚未初始化。

 mov dword ptr [ebp-48h],eax 

现在我们把刚才存储在堆栈中的那个引用复制到ecx中,它将用于指向调用ctor的“this”指针。

 mov ecx,dword ptr [ebp-48h] 

现在我们称之为Ctor。

 call FFE8A518 

现在我们把存储在临时堆栈槽中的引用再次复制到寄存器eax中。

 mov eax,dword ptr [ebp-48h] 

现在我们将eax中的引用复制到堆栈槽ebp-40中,这是a1。

 mov dword ptr [ebp-40h],eax 

现在我们必须把a1读入eax:

 a1.VarA = 5; mov eax,dword ptr [ebp-40h] 

请记住,eax现在是由a1引用的事物的堆分配数据的地址。 那东西的VarA字段是四个字节的对象,所以我们存储5:

 mov dword ptr [eax+4],5 

现在我们将a1的堆栈槽中的引用复制到eax中,然后将其复制到a2的堆栈槽中,即ebp-44。

 A a2 = a1; mov eax,dword ptr [ebp-40h] mov dword ptr [ebp-44h],eax 

现在,如你所期望的那样,我们得到a2进入eax,然后参照4个字节来将0x0A写入VarA:

 a2.VarA = 10; mov eax,dword ptr [ebp-44h] mov dword ptr [eax+4],0Ah 

所以你的问题的答案是对象的引用存储在堆栈中的三个地方:ebp-44,ebp-48和ebp-40。 它们被存储在eax和ecx的寄存器中。 对象的内存(包括其字段)存储在托pipe堆上。 这是在微软的CLR v4.0的debugging版本中的x86上。 如果你想知道堆栈中的东西是如何存储的,堆栈和注册在其他configuration中,可能会完全不同。 引用可以全部存储在堆中,或全部存储在寄存器中; 可能根本没有堆栈。 这完全取决于jit编译器的作者如何决定实现IL语义。

严格来说,这是依赖于实现的。 通常,.NET开发人员不应该关心这个问题。 据我所知,在Microsoft的.NET实现中,值types的variables存储在堆栈上(当它们在方法中声明的时候),引用types对象的数据被分配到一个托pipe堆上。 但是,请记住,当一个值types是一个类的字段时,类数据本身存储在一个堆(包括所有值types的字段)中。 因此,不要将语义(值types与引用types)与分配规则混合。 这件事情可能相关也可能不相关。

我想你可能会有轻微的误解

一般来说,引用types堆积如山,我相信价值types/本地人(可能是错误的)会堆积如山。 但是,您的A1.VarA和A2.VarA示例指的是引用types的字段 – 与堆中的对象一起存储…

在这种情况下,a1.VarA将在堆上,因为当您执行A a1 = new A()时,它将被分配空间。

如果你只是int i = 5; 在一个函数将会在堆栈上,但正如你明确指出的那样,a1将被分配在堆上,那么与它相关的所有值types将被放置在堆上

 class X { A a1=new A(); // reference on the stack, object value on the heap a1.VarA=5; // on the Heap- value type (Since it is inside a reference type) A a2=a1; // reference on the stack, object value on the heap a2.VarA=10; // on the Heap - value type (Since it is inside a reference type) } 

通过C#阅读Jeff Richter的CLR ,以全面了解这个主题。

请记住在C#深入阅读: – 只有局部variables(方法中声明的一个)和方法参数活在stack.Inventancevariables像varA在上面的情况下驻留在堆。

我也是C#的新手。 你的问题非常重要,我也想到了。 所有的文档都表示,值越来越多,引用也越来越多,但正如上面所说的那样,它只是代码里面的方法。 在学习的阶梯上,我意识到所有的程序代码都是从一个属于堆的实例的方法开始的。 所以概念上来说,堆栈与所有文档混淆了人们的堆栈并不相同。 堆栈机制只能在一个方法中find…