- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个像这样的 Main
方法:
static void Main(string[] args)
{
var b = new byte[1024 * 1024];
Func<double> f = () =>
{
new Random().NextBytes(b);
return b.Cast<int>().Average();
};
var avg = f();
Console.WriteLine(avg);
}
因为我在这里访问局部变量 b
,所以编译器创建了一个类来捕获该变量,并且 b
成为该类的字段。然后 b
的生命周期与编译器生成的类的生命周期一样长,它会导致内存泄漏。即使 b
超出范围(在这种情况下可能不会,但可以想象这是在另一个方法内部而不是 Main
),字节数组也不会被释放。
我想知道的是,因为在声明 Func
之后我没有在任何地方访问或修改 b
,为什么编译器不能内联那个局部变量而不用理会创建一个类?像这样:
Func<double> f = () =>
{
var b = new byte[1024 * 1024];
new Random().NextBytes(b);
return b.Cast<int>().Average();
};
我在 Debug 和 Release 模式下编译了这段代码,DisplayClass
是在两种模式下生成的:
这只是没有作为优化实现,还是我遗漏了什么?
最佳答案
Is this just not implemented as an optimization or is there anything I am missing?
对于您给出的具体示例,您可能不想进行该代码转换,因为它会改变程序的语义。如果 new
抛出异常,在原始程序中它应该在委托(delegate)执行之前抛出异常,而在您的转换中,副作用会被延迟。这是否是一个应该保留的重要属性(property)是值得商榷的。 (这样做也会给调试器带来问题;调试器已经必须假装闭包类的元素是包含方法体的局部元素,而这种优化可能会使它进一步复杂化。)
然而,更一般的一点是密切相关的。如果您知道封闭变量仅用于其值,则可以进行许多优化。
当我在编译器团队时——我于 2012 年离开——我和 Neal Gafter 考虑实现此类优化,以及一些更复杂的优化,旨在降低昂贵对象生命周期延长过长的可能性意外地。
旁白:最复杂的场景中最简单的是:我们将两个 lambda 转换为委托(delegate);一个存储在一个短暂的变量中,并在包含对昂贵对象的引用的局部变量上关闭;一个存储在一个长期存在的变量中,并在引用廉价对象的局部变量上关闭。昂贵的对象与长生命周期变量一样长,即使它没有被使用。更一般地,可以将多个闭包构造为基于封闭关系的分区;当时我们只根据嵌套来划分闭包;同一嵌套级别的闭包是一个闭包。给定的场景很少见,并且有明显的解决方法,但如果它根本没有发生就好了。
我们没有这样做是因为在我们实现 Roslyn 期间有更多重要的优化和功能,我们不想给已经很长的时间表增加风险。
我们可以自信地执行此类优化,因为在 C# 中,很容易知道本地何时被别名,因此您可以确定它是否在创建闭包后被写入。
我不知道这些优化是否同时实现了;可能不会。
我也不知道编译器是否对 C# 7 本地函数进行了此类优化,但我怀疑答案是"is"。看看如果您尝试使用本地函数会发生什么!
关于c# - 为什么编译器不能通过内联来优化闭包变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52087314/
以下闭包函数在 javascript 中运行良好。 function generateNextNumber(startNumber) { var current = startNumber;
Swift的闭包(Closures)是一种将功能块和上下文整合并演示在代码中的一种手段。闭包可以捕获并存储其上下文中的变量和常量。与普遍存在于其他语言的匿名函数(如Python的lambda、Java
在本教程中,您将借助示例了解 JavaScript 闭包。 在了解闭包之前,您需要了解两个概念: 嵌套函数 返回函数 JavaScript 嵌套函数 在 JavaScript 中,一个函数也可
在本教程中,您将借助示例了解 JavaScript 闭包。 在了解闭包之前,您需要了解两个概念: 嵌套函数 返回函数 JavaScript 嵌套函数 在 JavaScript 中,一个函数也可
闭包介绍 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 要理解闭包,首先必须理解Javascript特殊的变量作用域。 1.全局变量和局部变
这个问题已经有答案了: Methods in ES6 objects: using arrow functions (6 个回答) 已关闭 6 年前。 我已经在 stackoverflow 上到处查找
这个问题已经有答案了: How do JavaScript closures work? (86 个回答) 已关闭 9 年前。 我有一个关于 Javascript 闭包的简单问题: 给出了以下函数:
所以我有以下内容: Object a = data.getA(); Object b = data.getB(); Object c = data.getC(); // and so on 这些对象是
现在已经很晚了,我大脑中道格拉斯·克罗克福德居住的部分已经关闭。我尝试了一些方法,但没有达到预期效果。 我有一个 Canvas ,我在其中画了两条线,然后在计时器上淡出它们,但只有循环中的最后一行淡出
因此,我创建了一个变量 car,然后将其分配给一个函数并添加了参数模型、年份。然后在函数内引用参数创建一个对象。 然后创建“闭包”内部函数 yourCar() 并返回其中的外部函数对象“Propert
我正在 Mozilla 开发者网站上阅读关于关闭的解释,并且有点挣扎。请查看 Mozilla 网站上的以下代码。我有点理解它是如何工作的,但我认为我的评论下面的代码也应该工作。为什么一点击18、20就
这个问题在这里已经有了答案: UnboundLocalError trying to use a variable (supposed to be global) that is (re)assig
以下程序返回“本地”,根据我正在阅读的教程,它旨在演示闭包现象` 我不明白的是,为什么最后为了调用parentfunction,将其分配给变量“child”,然后调用“child”。 为什么只写 pa
我读到闭包末尾的()会立即执行。那么,这两者之间有什么区别。我在一些代码中看到了第一个用法。 谢谢。 for (var a=selectsomeobj(),i=0,len=a.length;i
代码如下 var collection = (function (){ var x = 0; return {
我仍然对 JavaScript 中的闭包概念感到困惑。我明白闭包是内部函数在母函数返回后访问在其母函数中创建的变量的能力。但是我仍然很困惑,如果我们可以在函数内部创建一个变量,为什么我们必须创建内部函
我搜索了很多主题并没有找到答案,或者问题太复杂了。所以没关系。这是我的第一个问题。 这是 SQL SELECT parent.*, ( SELECT COUNT(*) FROM
有 JS 高手可以解释为什么会这样吗: $$={} (function(x){ x.newModule = { func: function(){...} };
在此示例中,我尝试按值传递,但传递的是引用。 for (int i = 0; i new PhoneJobTest(i); t.Start(); } 这可以像这样补救: for (int
从 $.each() 中访问 this.rules 变量的最佳方式是什么?任何关于原因/方式的解释也会有帮助! app.Style = function(node) { this.style
我是一名优秀的程序员,十分优秀!