C# 编译器的优化程度如何?
How optimized is the C# compiler?
这段代码的IL代码(用https://dotnetfiddle.net生成):
public class Program
{
public static void Main()
{
int i = 10;
if (i < 4)
Console.WriteLine("Hello World");
}
}
包含 ldstr "Hello World".
编译器不应该知道 Console.WriteLine 永远不会被执行吗?
这个的IL代码:
public class Program
{
public static void Main()
{
if (10 < 4)
Console.WriteLine("Hello World");
}
}
不包含 ldstr 命令。
现在我很困惑.. .NET 编译器真的那么愚蠢吗?
两个示例的 C#/IL 代码的作用完全相同:什么都不做。但是第一个示例的 IL 代码比另一个大。一个好的编译器不应该只调用构造函数而不做任何事情吗?
编辑:
是的,我已经读过 this 但我不是在谈论额外生成的本地人。
如果 i
是属性或 public 变量,则可以从另一个线程修改它。但是 i
只存在于 Main()...
编译器的行为符合我的预期。编译器通常只评估常量和常量表达式,因为它们的值在编译时已知。您示例中的变量 "i" 和表达式 "i < 4" 在 运行 时计算,这就是编译器在这种情况下不优化代码的原因。
这是您的代码段的 x64 反汇编:
00007FF7C6083E0E add byte ptr [rax],al
--- C:\Dev\Temp\Test\ConsoleApp\ConsoleApp\Program.cs --------------------------
int i = 10;
00007FF7C6083E10 ret
--- No source file -------------------------------------------------------------
这意味着,JIT 执行了死代码消除(ret
= return,Main
函数只是立即退出)。
编译器只执行一些基本的优化,但大部分都留给了 JIT,以针对其运行的平台进行优化。
虽然我同意编译器在这种情况下当然可以执行此优化,因为它与平台无关。
我也认为这不应该是调试器的责任。虽然在你的样本中一切都很明显,但每一行都在计算值时显示累积影响,这是一个巨大的工作量,将其视为计算可用的国际象棋移动总数。 (国际象棋中可用的走法比宇宙中所有的星星多出数十亿步。)
这段代码的IL代码(用https://dotnetfiddle.net生成):
public class Program
{
public static void Main()
{
int i = 10;
if (i < 4)
Console.WriteLine("Hello World");
}
}
包含 ldstr "Hello World".
编译器不应该知道 Console.WriteLine 永远不会被执行吗?
这个的IL代码:
public class Program
{
public static void Main()
{
if (10 < 4)
Console.WriteLine("Hello World");
}
}
不包含 ldstr 命令。
现在我很困惑.. .NET 编译器真的那么愚蠢吗? 两个示例的 C#/IL 代码的作用完全相同:什么都不做。但是第一个示例的 IL 代码比另一个大。一个好的编译器不应该只调用构造函数而不做任何事情吗?
编辑:
是的,我已经读过 this 但我不是在谈论额外生成的本地人。
如果 i
是属性或 public 变量,则可以从另一个线程修改它。但是 i
只存在于 Main()...
编译器的行为符合我的预期。编译器通常只评估常量和常量表达式,因为它们的值在编译时已知。您示例中的变量 "i" 和表达式 "i < 4" 在 运行 时计算,这就是编译器在这种情况下不优化代码的原因。
这是您的代码段的 x64 反汇编:
00007FF7C6083E0E add byte ptr [rax],al
--- C:\Dev\Temp\Test\ConsoleApp\ConsoleApp\Program.cs --------------------------
int i = 10;
00007FF7C6083E10 ret
--- No source file -------------------------------------------------------------
这意味着,JIT 执行了死代码消除(ret
= return,Main
函数只是立即退出)。
编译器只执行一些基本的优化,但大部分都留给了 JIT,以针对其运行的平台进行优化。
虽然我同意编译器在这种情况下当然可以执行此优化,因为它与平台无关。
我也认为这不应该是调试器的责任。虽然在你的样本中一切都很明显,但每一行都在计算值时显示累积影响,这是一个巨大的工作量,将其视为计算可用的国际象棋移动总数。 (国际象棋中可用的走法比宇宙中所有的星星多出数十亿步。)