为什么C#编译器不会优化掉重复的局部变量默认值初始化?

5

背景

我知道编译器会“忽略为字段生成代码,例如int foo = 0;,因为内存分配器会将字段初始化为默认值。”参考资料

        class Foo
        {
            public int a = 1;
            public int b = 0;
        }
        Foo..ctor:
        IL_0000:  ldarg.0     
        IL_0001:  ldc.i4.1
        IL_0002:  stfld       UserQuery+Foo.a // There is no b.
        IL_0007:  ldarg.0
        IL_0008:  call        System.Object..ctor
        IL_000D:  ret

我知道"编译器会在使用局部变量的每个方法上自动添加.locals init,表示JIT必须在开始执行方法之前注入初始化所有局部变量的代码。"参考链接

问题

为什么编译器不会省略生成用于本地变量的IL代码,例如int foo = 0;,因为.locals init已经涵盖了这一点?(为了与字段保持一致性?)

(我理解C#规范要求局部变量被明确分配,我可以接受这一点。)

(我引用的链接说明了为什么需要.locals init,以及为什么C#规范要求局部变量被初始化。但它没有说明为什么必须存在额外的IL指令来初始化默认值。由于验证过程已经由.locals init保证)

void Main()
{
    int a = 0;
    int b = 1;
    int c = 0;
    int d = a + b + c;
    d++;
}

.maxstack 2
.locals init (int a, int b, int c, int d)

IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     // a (Can be optimized away)
IL_0002:  ldc.i4.1    
IL_0003:  stloc.1     // b
IL_0004:  ldc.i4.0    
IL_0005:  stloc.2     // c (Can be optimized away)
IL_0006:  ldloc.0     // a
IL_0007:  ldloc.1     // b
IL_0008:  add         
IL_0009:  ldloc.2     // c
IL_000A:  add         
IL_000B:  stloc.3     // d
IL_000C:  ldloc.3     // d
IL_000D:  ldc.i4.1    
IL_000E:  add         
IL_000F:  stloc.3     // d

好的,现在我明白你的意思了,因为你解释了这个例子。 - EkoostikMartin
2
好像https://dev59.com/j0fRa4cB1Zd3GeqP7Tox#3383168回答了这个问题。 - Jim Mischel
1
@JimMischel 我认为https://dev59.com/j0fRa4cB1Zd3GeqP7Tox#3383168并没有回答问题。它说了为什么`.locals init很重要,以及为什么C#规范要求必须初始化本地变量。但是它并没有说为什么必须存在额外的IL指令。(因为.locals init`已经确保了验证过程) - colinfang
@JimMischel 关于您最后一句话:这就是编译器坚持在C#代码中进行显式初始化的原因,但这并不能解释为什么显式初始化在IL中保留。您之前说的基本上已经解释了这一点,但这与错误无关。 - svick
@JimMischel 我知道在本地变量的情况下没有性能差异。但是在字段的情况下也没有区别。而且它们会对字段进行优化,为什么不对变量做同样的事情呢? - colinfang
显示剩余5条评论
1个回答

1
为什么编译器不会省略像 int foo = 0; 这样的局部变量生成IL代码,因为 .locals init 已经覆盖了这个呢? 为什么要这样做呢?我没有实际验证过,但如果您删除不必要的初始化,JIT编译器生成的本机代码可能会有所不同,这让我感到惊讶。 这意味着,将此优化添加到C#编译器中的唯一好处是使JIT编译速度更快(因为它必须处理更少的IL代码)。 C#编译器的作者似乎认为,为了如此微小的好处而进行这种优化是不值得的。

我理解在本地变量的情况下没有性能差异。但是在字段的情况下也没有区别。而且它们会对字段进行优化,为什么不对变量做同样的优化呢? - colinfang
@colinfang 我认为“生成一致的IL”在C#团队的优先事项列表中非常低。 - svick
它可能想这样做以优化IL大小并减少在JIT中花费的时间。但它可能不在优先列表的高位。 - usr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接