C#Lambda =>生成垃圾吗?

Nap*_*eon 24 c# linq garbage

使用lambda表达式是否会为与正常foreach循环相对的GC生成垃圾?

// Lambda version
Foos.ForEach(f=>f.Update(gameTime));

// Normal approach:
foreach (Foo f in Foos)
{
  f.Update(gameTime);
}
Run Code Online (Sandbox Code Playgroud)

CLR分析器显示我有69.9%system.Action <T>并且我怀疑是如上所述的foreach循环的lamba版本.真的吗?

编辑:我使用Microsoft CLR分析器:http://download.microsoft.com/download/4/4/2/442d67c7-a1c1-4884-9715-803a7b485b82/clr%20profiler.exehttp://msdn.microsoft .COM/EN-US /库/ ff650691.aspx

Gab*_*abe 24

是的,如果闭包从本地范围捕获变量(即gameTime在此上下文中),则lambda将创建垃圾.

例如,以下C#函数:

static void TestLambda(List<Foo> Foos, DateTime gameTime)
{
    Foos.ForEach(f => f.Update(gameTime));
}
Run Code Online (Sandbox Code Playgroud)

将被翻译为:

private static void TestLambda(List<Foo> Foos, DateTime gameTime)
{
    Program.<>c__DisplayClass1 <>c__DisplayClass = new Program.<>c__DisplayClass1();
    <>c__DisplayClass.gameTime = gameTime;
    Foos.ForEach(new Action<Foo>(<>c__DisplayClass.<TestLambda>b__0));
}
Run Code Online (Sandbox Code Playgroud)

请注意,结果代码中有两个实例new,这意味着不仅Action要分配对象(闭包),还要保存捕获变量的对象(转义变量记录).

  • @Chris:不完全正确.因为生成的方法必须引用"gameTime",所以它不能是静态的.要测试这一点,请尝试创建一个使用静态方法而不是委托的OP代码版本.这里绝对需要关闭.可能有一个为委托创建的新"类型",假设程序集中没有其他委托共享相同的闭包签名,但这不是GC问题.GC问题是,当创建`Action`时,还有一个额外的指针,否则就没有了.它在那里,但它是微不足道的. (3认同)
  • @Chris,Stripling是对的.你混淆了两个不同的概念.闭包都需要由编译器生成隐藏类型*和*要创建的该类型的实例.你是正确的,只是必须*定义*类型一次.但是必须在每次执行封闭上下文时*实例化*. (2认同)
  • @Chris:如果你的列表中有1000个元素,调用`Foos.ForEach(x => x)`将创建1个委托,而不是1000.但是,如果你的程序主要做`.ForEach()`那么代表将开始变成很多垃圾. (2认同)