请考虑以下代码示例:
static voID Main(string[] args){ Foo(false,8);}public static voID Foo(bool execute,int x){ if (execute) { Task.Run(() => Console.Writeline(x)); }}
运行此(在发布中)显示发生了一些意外的分配.检查IL表明闭包触发的堆分配出现在函数的最开头,而不是在条件内:
.method public hIDebysig static voID Foo( bool execute,int32 x ) cil managed { .maxstack 2 .locals init ( [0] class Test.Program/'<>c__displayClass1_0' 'CS$<>8__locals0' ) IL_0000: newobj instance voID Test.Program/'<>c__displayClass1_0'::.ctor() IL_0005: stloc.0 // 'CS$<>8__locals0' IL_0006: ldloc.0 // 'CS$<>8__locals0' IL_0007: ldarg.1 // x IL_0008: stfld int32 Test.Program/'<>c__displayClass1_0'::x // [18 13 - 18 25] IL_000d: ldarg.0 // execute IL_000e: brfalse.s IL_0022 // [20 17 - 20 54] IL_0010: ldloc.0 // 'CS$<>8__locals0' IL_0011: ldftn instance voID Test.Program/'<>c__displayClass1_0'::'<Foo>b__0'() IL_0017: newobj instance voID [mscorlib]System.Action::.ctor(object,native int) IL_001c: call class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Threading.Tasks.Task::Run(class [mscorlib]System.Action) IL_0021: pop // [22 9 - 22 10] IL_0022: ret } // end of method Program::Foo
我在这里遗漏了什么,是否有人对这种奇怪的行为有解释? Roslyn是否可能生成为闭包分配的代码,无论我们是否实际执行它们?
解决方法 此行为是设计使然.当你的方法有一个闭包时,闭包内使用的所有变量都必须是闭包类的一部分(这样lambda就可以访问它们的当前值).
如果编译器没有立即分配闭包,则在创建闭包实例时,必须将值从局部变量复制到闭包类的字段,浪费时间和内存.
如果具有不同可达性(或者更糟的是嵌套范围)的多个lambda靠近相同的变量,那么这也会使codegen风险更大,更复杂.
总结以上是内存溢出为你收集整理的C#闭包堆分配在方法开始时发生全部内容,希望文章能够帮你解决C#闭包堆分配在方法开始时发生所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)