c# - 为什么方法组会导致堆分配?
问题描述
我正在阅读https://blog.jetbrains.com/dotnet/2019/01/23/c-classes-memory-snapshots/并提到使用“方法组而不是 lambda”,它正确地指出:
我们想知道这种方法是否会产生内存流量。快速查看反编译的代码会说是的,不幸的是,它会的。
但是,不幸的是,他们没有解释为什么。
我在https://sharplab.io/创建了自己的示例:
using System;
using System.Collections.Generic;
using System.Linq;
public class ClassWithAllocation {
private string selector(string y){
return y + this.GetHashCode(); //random example to demonstrate use of `this`
}
public void Method() {
var source= new List<string>();
source.Select(selector); //compiled to: Enumerable.Select(source, new Func<string, string>(selector));
}
}
如评论中所述,编译为在每次调用selector
时创建一个。new Func
当使用不带闭包的 lambda 时,C# 会缓存一个Func
可用于每次调用的实例。(并且:使用闭包这是不可能的,因为每次调用都必须“保留”不同的上下文。)
但是为什么上面的代码不能编译成下面这样的东西呢?
public class ClassWithoutAllocation {
private readonly Func<string,string> _selector;
public ClassWithoutAllocation(){
_selector = new Func<string, string>(selector);
}
private string selector(string y){
return y + this.GetHashCode(); //random example to demonstrate use of `this`
}
public void Method() {
var source= new List<string>();
source.Select(_selector); //compiled to: Enumerable.Select(source, _selector);
}
}
SharpLab 显示代码基本上是按原样编译的。
后续问题:就是这样,上述模式(存储Func
要使用的而不是方法组)是避免堆分配的好模式吗?
编辑
这个问题被关闭作为调用 func 时为什么有内存分配的假设副本。但是,正如@JonSkeet 在他的回答中所说:
不幸的是,C# 5 规范目前要求在每次运行时创建一个新的委托实例。
所有这一切都让我感到难过,在最新版本的 ECMA C# 标准中,编译器将被允许缓存方法组转换的结果。我不知道它何时/是否会这样做。
所以,我仍然想知道为什么编译器不会像我上面的示例那样缓存引用(这比链接问题中的更简单)?不这样做有什么好处?这样做有什么弊端?
解决方案
推荐阅读
- arm - Cortex-M0 硬故障处理程序在更改后不会被调用
- wordpress - WooCommerce Paypal - 不允许基于 PayPal 帐单地址的付款(国家/地区限制)
- google-apps-script - 在与当前文件相同的文件夹中创建一个谷歌电子表格
- google-chrome - 当我在 v86 中打开开发工具时,Chrome 在刷新页面后不会释放内存
- reactjs - 将 Create-React-App 与 Apache VirtualHost 一起使用
- wcf-ria-services - OpenRiaServices 异步方法
- powershell - 是否可以在 PSObject 中为“for”做一个“for”?
- javascript - 使用 Javascript 访问 iFrame 中的 DOM
- c++ - 如何将程序中的所有变量初始化为零而不在c ++中显式执行
- html - 从选择框中选择一个值并使用 jquery 从另一个选择框中自动选择一个值