Pet*_*etr 13 c# stack memory-management
如果有人能告诉我我是否理解它,我真的很感激:
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
}
Run Code Online (Sandbox Code Playgroud)
此外a1,a2引用都在堆栈上,而它们的"对象"值在堆上.但是VarA变量,它仍然是纯粹的价值类型呢?
class A
{
int VarA;
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 27
您正在询问有关实现细节的问题,因此答案取决于具体实现.让我们考虑一下实际编译的程序版本:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是在Microsoft的CLR 4.0上运行C#4.0,在调试模式下发生的事情.
此时堆栈帧指针已被复制到寄存器ebp中:
这里我们为新对象分配堆内存.
A a1 = new A();
mov ecx,382518h
call FFE6FD30
Run Code Online (Sandbox Code Playgroud)
它返回对eax中的堆对象的引用.我们将引用存储在堆栈槽ebp-48中,这是一个与任何名称无关的临时槽.请记住,a1尚未初始化.
mov dword ptr [ebp-48h],eax
Run Code Online (Sandbox Code Playgroud)
现在我们将我们刚刚存储在堆栈中的引用复制到ecx中,ecx将用于指向ctor调用的"this"指针.
mov ecx,dword ptr [ebp-48h]
Run Code Online (Sandbox Code Playgroud)
现在我们打电话给ctor.
call FFE8A518
Run Code Online (Sandbox Code Playgroud)
现在我们再次将存储在临时堆栈槽中的引用复制到寄存器eax中.
mov eax,dword ptr [ebp-48h]
Run Code Online (Sandbox Code Playgroud)
现在我们将eax中的引用复制到堆栈槽ebp-40,即a1.
mov dword ptr [ebp-40h],eax
Run Code Online (Sandbox Code Playgroud)
现在我们必须将a1取入eax:
a1.VarA = 5;
mov eax,dword ptr [ebp-40h]
Run Code Online (Sandbox Code Playgroud)
请记住,eax现在是a1引用的事物的堆分配数据的地址.那个东西的VarA字段是对象的四个字节,所以我们将5存储到:
mov dword ptr [eax+4],5
Run Code Online (Sandbox Code Playgroud)
现在我们将堆栈槽中的引用副本复制为a1到eax,然后将其复制到a2的堆栈槽中,即ebp-44.
A a2 = a1;
mov eax,dword ptr [ebp-40h]
mov dword ptr [ebp-44h],eax
Run Code Online (Sandbox Code Playgroud)
现在你再次期待我们将a2转换为eax,然后将参考四个字节用于将0x0A写入VarA:
a2.VarA = 10;
mov eax,dword ptr [ebp-44h]
mov dword ptr [eax+4],0Ah
Run Code Online (Sandbox Code Playgroud)
所以你的问题的答案是对象的引用存储在三个位置:ebp-44,ebp-48和ebp-40.它们存储在eax和ecx的寄存器中.对象的内存(包括其字段)存储在托管堆上.这是微软CLR v4.0的调试版本中的x86.如果你想知道堆栈,堆和寄存器在其他配置中的存储方式,它可能完全不同.引用都可以存储在堆上,或者全部存储在寄存器中; 可能根本就没有堆栈.这完全取决于jit编译器的作者如何决定实现IL语义.
n53*_*535 10
严格来说,它依赖于实现.通常,.NET开发人员不应该关心这些事情.据我所知,在Microsoft的.NET实现中,值类型的变量存储在堆栈中(当它们在方法中声明时),并且引用类型对象的数据在托管堆上分配.但是,请记住,当值类型是类的字段时,类数据本身存储在堆上(包括所有值类型字段).因此,不要将语义(值类型与引用类型)与分配规则混合在一起.这些东西可能相关也可能不相关.