fly*_*bug 38 .net c# compiler-optimization
我有一段这样的代码:
if (state != "Ok")
{
Debug.WriteLine($"Error occured: {state}, {moreInfo}");
}
Run Code Online (Sandbox Code Playgroud)
如果我发布版本,编译器是否会优化它?或者评估是否仍然存在,从而花费一些处理时间?
Pat*_*man 48
是的,它确实如此,至少对于Debug电话而言.我在这里看不到JIT编译器是否也删除了它的评估if,但我想它确实如此,因为该等式没有任何副作用.
但是,最好通过调用来保证安全Debug.WriteLineIf,这不依赖于JIT编译器来删除评估.
为了完整性,编译器要删除的证明Debug.WriteLine.
发布版本中的代码:
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 17 (0x11)
.maxstack 8
IL_0000: call string [mscorlib]System.Console::ReadLine()
IL_0005: ldstr "Ok"
IL_000a: call bool [mscorlib]System.String::op_Inequality(string,
string)
IL_000f: pop
IL_0010: ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)
Debug构建中的代码:
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 42 (0x2a)
.maxstack 2
.locals init ([0] string state,
[1] bool V_1)
IL_0000: nop
IL_0001: call string [mscorlib]System.Console::ReadLine()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr "Ok"
IL_000d: call bool [mscorlib]System.String::op_Inequality(string,
string)
IL_0012: stloc.1
IL_0013: ldloc.1
IL_0014: brfalse.s IL_0029
IL_0016: nop
IL_0017: ldstr "Error occured: {0}"
IL_001c: ldloc.0
IL_001d: call string [mscorlib]System.String::Format(string,
object)
IL_0022: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0027: nop
IL_0028: nop
IL_0029: ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)
如您所见,Release模式没有调用Debug.WriteLine,Debug模式的调用方式.
Abi*_*n47 15
如果您使用
Debug类中的方法来打印调试信息并使用断言检查逻辑,则可以使代码更加健壮,而不会影响运输产品的性能和代码大小....
该
ConditionalAttribute属性应用于方法Debug.ConditionalAttribute除非"DEBUG"被定义为条件编译符号,否则支持忽略对这些方法的调用的编译器.
如您所见,编译器将忽略Debug对非调试版本的成员的任何调用.但是,它不会阻止程序检查您的if语句.如果您希望编译器也忽略if语句,您可以使用预处理器指令将整个块包含在内,如下所示:
#if DEBUG
if (state != "Ok")
{
Debug.WriteLine($"Error occured: {state}, {moreInfo}");
}
#endif
Run Code Online (Sandbox Code Playgroud)
C#编译器是由语言规范要求删除Debug通话和它的参数的评估。
如果 .NET JIT 是一个复杂的 JIT,它将确定字符串方法调用没有副作用并且可以删除。.NET JIT 不是很复杂,所以实际上它仍然有机会调用该方法。让我们来了解一下。
在发布模式下编译程序,反编译它并在 4.6.2 上以 x64 运行它,而没有调试器抑制优化。
static void Main()
{
var state = GetState();
if (state != "Ok")
{
Debug.WriteLine(state);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static string GetState()
{
return "x";
}
Run Code Online (Sandbox Code Playgroud)
C# 编译器保持字符串不等式调用不变:
我不确定规范是否允许优化它,因为这可能是一种副作用方法。不确定编译器可以对其进行假设。
我们出色的 JIT 也没有删除调用:
(1) 是GetState()和 (2) 是string.!=。
使用Debug.WriteLineIf原因:
17.4.2.1 条件方法 用 Conditional 属性修饰的方法是条件方法。Conditional 属性通过测试条件编译符号来指示条件。包含或省略对条件方法的调用取决于此符号是否在调用点定义。如果定义了符号,则包括调用;否则,调用(包括接收者的评估和调用的参数)将被省略。
| 归档时间: |
|
| 查看次数: |
2660 次 |
| 最近记录: |