【问题标题】:Where is the captured variables allocated in nested function in C#在 C# 的嵌套函数中分配的捕获变量在哪里
【发布时间】:2018-10-09 11:36:50
【问题描述】:

提到的嵌套函数意味着它既可以是 lambda 函数,也可以是本地函数。

我很好奇捕获的变量分配在哪里。

例如:

private Func<int> Test(int arg)
{
    var x = arg;
    return () => x;
}

局部变量x被返回的lambda函数捕获。

那么这个x在内存中分配在哪里呢?是在栈内存还是堆内存上?

如果此 x 在堆栈上,则对 Test 的任何进一步调用都可能更改 x 的值,并且返回的 lambda 函数的行为可能会被错误地修改。

但是如果它在堆内存上动态分配的,它就不再像一个局部变量了。

它是否首先在堆栈中分配并在Test 返回时转移到堆中? (我猜不是因为这听起来像是不必要地消耗了一些资源,而是在Test 返回后使它可以访问这个x 是如何工作的?)

【问题讨论】:

  • 语义上,无论分配细节如何,每次调用Test 都会有一个不同的(或“新鲜”)变量x。因此,没有两个函数/闭包返回(来自不同的调用)可以访问相同的 x 变量或直接交互。
  • Func&lt;T&gt; 是代表。不确定是否与您的问题有关:stackoverflow.com/questions/20357737/…
  • 每个人都知道它的行为方式,但这并不完全是问题,即如何分配捕获的局部变量以及如何分配捕获的局部变量以使其行为如此。 @user2864740
  • 很明显x 不能在堆栈上分配,因为它的生命周期超出了创建它的方法的范围。
  • 它没有指定如何捕获局部变量,所以它与我的问题有关。 @ChristianGollhardt

标签: c# .net memory lambda


【解决方案1】:

堆栈与堆在这里不是一个非常有用的区别,但我可以让您了解会发生什么。编译器在幕后重写这段代码。它将一个类添加到项目中,该类具有一个整数值作为成员。然后这个函数和 lambda 函数都获得了对这个新类的同一个实例的引用。

至少,这就是我上次读到它时的处理方式,诚然,这是不久前的事了……但我怀疑它已经改变了很多。欢迎来到编程,您认为自己知道的一切实际上都是过去某个时间事物的快照。

【讨论】:

  • 根据 dotMemory 分析,这看起来仍然是真的。 imgur.com/a/fTMbtNH
  • 非常感谢,所以只要捕获了局部变量,就不再是简单的局部变量了,是吗?那么我们是否应该避免在嵌套函数中使用局部变量捕获而使用参数传递,以避免生成的捕获上下文的额外内存成本?
  • 在性能分析器告诉您担心它之前,您应该不用担心它。代码的清晰度和可维护性,只有当你的工具告诉你它实际上导致了问题时,才担心这样的微优化。
  • 但是如果我想创建一个算法并希望它尽可能快地运行呢?
  • 那么你肯定想要使用分析器,而不是猜测程序的哪些部分让事情变慢。
猜你喜欢
  • 2020-10-18
  • 1970-01-01
  • 1970-01-01
  • 2015-03-13
  • 2011-07-20
  • 1970-01-01
  • 2016-02-07
  • 2020-06-08
  • 2014-12-27
相关资源
最近更新 更多