c# – 为什么编译器不能通过内联优化闭包变量?

前端之家收集整理的这篇文章主要介绍了c# – 为什么编译器不能通过内联优化闭包变量?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个像这样的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超出范围(可能不是在这种情况下,但想象这是在另一个方法而不是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抛出异常,在原始程序中它应该在执行委托之前这样做,并且在转换中,副作用被推迟.这是否是一个应该保留的重要财产是值得商榷的. (这样做也会给调试器带来问题;调试器必须假装闭包类的元素是包含方法体的本地元素,并且这种优化可能会使其进一步复杂化.)

然而,更普遍的一点是密切相关.如果您知道封闭变量仅用于其值,则可以执行许多优化.

当我参加编译团队时 – 我在2012年离职 – 我和Neal Gafter考虑实施这样的优化,以及一些更复杂的优化,旨在降低昂贵对象的生命周期长时间延长的可能性.

旁白:最复杂的场景中最简单的是:我们将两个lambdas转换为委托;一个存储在一个短期变量中,并在一个包含对昂贵对象的引用的本地上关闭;一个存储在一个长期存在的变量中,并在一个引用廉价对象的本地上关闭.即使没有使用,昂贵的物体也会存在长寿命变量.更一般地,可以基于封闭关系将多个闭包构造为分区;当时我们只基于嵌套来分区闭包;在同一嵌套层面的封闭是一个封闭.给定的场景很少见,并且有明显的解决方法,但如果它根本没有发生会很好.

我们没有这样做,因为在我们实施Roslyn期间有更重要的优化和功能,我们不想为已经很长的时间表增加风险.

我们可以自信地执行这样的优化,因为在C#中很容易知道本地何时被别名化,因此您可以确定是否在创建闭包之后写入它.

我不知道这些优化是否已经同时实施;可能不是.

我也不知道编译器是否对C#7本地函数进行了这样的优化,但我怀疑答案是肯定的.看看如果尝试本地功能会发生什么!

猜你在找的C#相关文章