C# 为什么';编译器优化掉重复的局部变量默认值初始化? 背景
我知道编译器会“忽略为字段生成代码,比如C# 为什么';编译器优化掉重复的局部变量默认值初始化? 背景,c#,clr,il,C#,Clr,Il,我知道编译器会“忽略为字段生成代码,比如intfoo=0;,因为内存分配器会将字段初始化为默认值。” 我还知道“编译器会在每个使用局部变量的方法上自动添加.locals init,这表明JIT必须在开始执行方法之前注入初始化所有局部变量的代码。” 问题: 为什么编译器不忽略为intfoo=0?(是否与字段一致?) (我理解C#规范要求明确指定局部变量,我同意。) (我引用的链接说明了为什么需要.locals init,以及为什么C#spec要求初始化局部变量。但它没有说明为什么必须存在初始化默认
intfoo=0;
,因为内存分配器会将字段初始化为默认值。”
我还知道“编译器会在每个使用局部变量的方法上自动添加.locals init
,这表明JIT必须在开始执行方法之前注入初始化所有局部变量的代码。”
问题:
为什么编译器不忽略为intfoo=0因为.locals init
已经涵盖了局部变量的代码>?(是否与字段一致?)
(我理解C#规范要求明确指定局部变量,我同意。)
(我引用的链接说明了为什么需要.locals init
,以及为什么C#spec要求初始化局部变量。但它没有说明为什么必须存在初始化默认值的附加IL指令。因为验证过程已经由.locals init
确定了)
为什么编译器不忽略为intfoo=0因为.locals init
已经涵盖了局部变量的代码>
为什么要这样做?我还没有实际验证过这一点,但是如果删除了不必要的初始化,JIT编译器会生成不同的本机代码,我会感到惊讶
这意味着,将这种优化添加到C#编译器中的唯一好处是使JIT编译稍微快一点(因为它必须处理更少的IL代码)。C#编译器的作者们似乎认为,为了这么小的好处而进行这种优化是不值得的。是否.locals init
涵盖了这种情况?这些是成员变量而不是局部变量,因此处理方式不同?好吧,我明白你的意思了,你澄清了这个例子。似乎回答了这个问题。如果我猜,我会说这与变量的碳足迹有关,当方法执行完后,它将被gc处理,该类必须使用idisposable@JimMischel我不认为答案。它说明了为什么.locals init
非常重要,以及为什么C#spec要求初始化局部变量。但它没有说明为什么必须存在额外的IL指令。(由于验证过程由.locals init
保证)我知道局部变量情况下没有性能差异。但在现场案例中也没有区别。而且他们确实在字段上进行了优化,为什么不在变量上进行同样的优化呢?@colinfang我认为“生成一致的IL”在C#团队的优先级列表中是非常低的。它可能希望这样做来优化IL大小并减少在JIT上花费的时间。不过,这个数字可能还不够高。
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
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