我想知道字段固定是如何用.Net的IL语言表达的,所以我看了一下示例代码:
struct S { public fixed int buf[8]; } S s = default(S); public void MyMethod() { fixed (int* ptr = s.buf){ *ptr = 2; } }
这会生成IL:
.method private hidebysig instance void MyMethod () cil managed { // Method begins at RVA 0x2050 // Code size 25 (0x19) .maxstack 2 .locals init ( [0] int32& pinned ) IL_0000: ldarg.0 // Load argument 0 onto the stack IL_0001: ldflda valuetype C/S C::s // Push the address of field of object obj on the stack IL_0006: ldflda valuetype C/S/'e__FixedBuffer' C/S::buf // Push the address of field of object obj on the stack IL_000b: ldflda int32 C/S/' e__FixedBuffer'::FixedElementField // Push the address of field of object obj on the stack IL_0010: stloc.0 // Pop a value from stack into local variable 0 IL_0011: ldloc.0 // Load local variable 0 onto stack IL_0012: conv.i // Convert to native int, pushing native int on stack IL_0013: ldc.i4.2 // Push 2 onto the stack as int32 IL_0014: stind.i4 // Store value of type int32 into memory at address IL_0015: ldc.i4.0 // Push 0 onto the stack as int32 IL_0016: conv.u // Convert to native unsigned int, pushing native int on stack IL_0017: stloc.0 // Pop a value from stack into local variable 0 IL_0018: ret // Return from method, possibly with a value } // end of method C::MyMethod
我在这里没有看到任何东西,它会明确地告诉GC固定数组,哪条指令实际上负责固定?还有,其他基本操作涉及钉在"引擎盖下"吗?
.locals init ( [0] int32& pinned )
使用pinned
是负责钉扎.本文解释了它:'fixed'关键字如何工作?本文指出标准ECMA-335公共语言基础结构(CLI)的以下摘录:
II.7.1.2固定
固定的签名编码只出现在描述局部变量的签名中(§II.15.4.1.3).当一个带有固定局部变量的方法正在执行时,VES不应该重新定位本地引用的对象.也就是说,如果CLI的实现使用移动对象的垃圾收集器,则收集器不应移动由活动的固定局部变量引用的对象.
[基本原理:如果使用非托管指针取消引用托管对象,则应固定这些对象.例如,当托管对象传递给设计用于处理非托管数据的方法时,就会发生这种情况.最终理由]
VES =虚拟执行系统,CLI =公共语言基础结构