C#对象创建的汇编代码解析:为何存在两次调用?
为什么C#代码
A a = new A();对应的汇编有两次call指令? 先看你给出的C#代码和对应的汇编指令:
C#代码:
A a = new A();
对应的汇编指令:
012E2FB8 mov ecx,58812BCh 012E2FBD call 011C30F4 012E2FC2 mov dword ptr [ebp-44h],eax 012E2FC5 mov ecx,dword ptr [ebp-44h] 012E2FC8 call 012E0D60 012E2FCD mov eax,dword ptr [ebp-44h] 012E2FD0 mov dword ptr [ebp-40h],eax
这两次call其实对应了CLR创建对象的两个关键步骤,我给你拆解下:
第一次
call 011C30F4:这是调用.NET运行时的内存分配底层方法(比如GC.AllocateNewObject)。当你执行new A()时,CLR首先得在托管堆上为A的实例分配一块合适的内存空间,这个call就是干这件事的——执行完后,eax寄存器里会存着刚分配好的内存地址(也就是对象的引用),然后代码把这个地址存在栈上的[ebp-44h]位置暂存。第二次
call 012E0D60:这是调用类A的实例构造函数(.ctor)。内存分配完还不算完,对象得初始化才能用对吧?这里把刚才存的对象地址放到ecx寄存器(这是C#实例方法的调用约定,ecx用来传递this指针),然后调用构造函数,执行里面的初始化逻辑(比如给成员变量赋值、执行构造代码块等)。
等这两步都完成后,代码才把对象引用赋值给变量a(最后两行把地址从[ebp-44h]移到[ebp-40h],这个位置对应变量a在栈上的存储)。
所以本质上,new关键字在CLR层面就是拆成了「分配内存」+「初始化对象」两个独立操作,自然就对应了两次call指令啦。
内容的提问来源于stack exchange,提问作者SegmentationFault
相关产品推荐
相关产品推荐

