[英]Are these objects's references on the Stack or on the Heap?
如果有人能告诉我我是否了解我,我将不胜感激:
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
}
同样, a1
和a2
引用都在堆栈上,而它们的“对象”值在堆上。 但是VarA
变量,它仍然是纯值类型呢?
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;
}
}
这是在调试模式下运行C#4.0的Microsoft 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中,然后将参考引用四个字节,以将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中的寄存器中。 对象的内存(包括其字段)存储在托管堆中。 这一切都在Microsoft CLR v4.0的调试版本的x86上完成。 如果您想知道东西如何以其他配置存储在堆栈,堆和寄存器中,则可能完全不同。 引用可以全部存储在堆中,也可以全部存储在寄存器中。 可能根本没有堆栈。 这完全取决于jit编译器的作者决定实现IL语义的方式。
严格来说,它取决于实现。 通常,.NET开发人员不应该关心这些事情。 据我所知,在Microsoft .NET的实现中,值类型的变量存储在堆栈中(在方法中声明它们时),引用类型对象的数据分配在托管堆上。 但是请记住,当值类型是类的字段时,类数据本身会存储在堆中(包括所有值类型字段)。 因此,请勿将语义(值类型与引用类型)与分配规则混合使用。 这件事可能相关也可能不相关。
我想您可能会有一点误会...
一般而言,引用类型进入堆栈,而我认为(可能是错误的)值类型/本地变量进入堆栈。 但是,您的A1.VarA和A2.VarA示例引用的是引用类型的字段-该字段与对象一起存储在堆中...
在这种情况下,a1.VarA将在堆上,因为当您执行A a1 = new A()
时将为其分配空间。
如果你只是做int i = 5;
在将要在堆栈上的函数中,但是正如您明确声明的那样,将a1分配在堆上,然后与之关联的所有值类型都将放置在堆上
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#中深入阅读:-只有局部变量(在方法内部声明的变量)和方法参数存在于堆栈中。实例变量如varA在上述情况下位于堆中。
我也是C#的新手。 您的问题非常重要,我也想到了。 所有文档都说,值进入堆栈,引用进入堆,但是正如上面的人所说,它仅用于方法内部的代码。 在学习的阶梯上,我意识到所有程序代码都始于一个方法的内部,该方法属于一个属于堆的实例。 因此,从概念上讲,堆栈在术语上与堆不相等,就像所有文档使人们感到困惑一样。 仅在一种方法中发现堆栈机制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.