2016-12-06 61 views
4

网上有很多文章列出了在执行一段代码之前C#JIT所做的优化。例如this post MSDN上谈到:C#JIT编译器是否优化了空检查?

常量折叠,常量和复制传播,普通的子表达式 消除,循环不变,死存储和死码 消除代码运动,寄存器分配,方法内联,循环展开 (带小体的小环)。

我的问题是:JIT编译器是否也处理无用的空检查?我无法找到任何来源来处理这个问题。

在同一篇文章我读:

,因为C#语言规范确保了空 对象引用任何调用抛出一个NullReferenceException,每次调用站点必须 确保实例不为空。这是通过取消引用 实例引用完成的;如果它为空,它将产生一个故障,即 变成此异常。

因此,假设我写一段代码是这样的:再次

if (person != null) 
{ 
    Console.WriteLine(person.Name); 
} 

person.Name调用第二空检查是克利里没用,编译器可以将其删除。或不?

,我读了在Java中,这是已经完成(很多hereherehere之间的一些消息来源)。

如果C#也这样做,你知道一些来源或文件谈论?

如果C#没有这样做,你知道为什么吗? Java JIT没有遇到的.NET环境中实现这样的功能是否存在固有的困难?

+2

仅作为正常优化的副作用,如死码消除。这应该是非常罕见的。一般来说,抖动优化器对执行空指针检查的代码没有特别的了解,并将指针视为易失性。在任何具有垃圾收集器的虚拟机中非常重要,该收集器在压缩堆时任意修改指针。值得注意的是,C#编译器本身可以消除检查,当你使用elvis操作符('?.')时它会这样做。 –

回答

3

Null检查优化由编译器(Roslyn,而不是抖动)in several cases,当它完全保存做到这一点。

例如,当您使用?(埃尔维斯算子)。

IL_0006: stloc.0    // Pop a value from stack into local variable 0 
IL_0007: ldloc.0    // Load local variable 0 onto stack 
IL_0008: brtrue.s IL_000c  // Branch to target if value is non-zero (true), short form 
IL_000a: br.s IL_0013   // Branch to target, short form 
IL_000c: ldloc.0    // Load local variable 0 onto stack 
IL_000d: call instance void Foo::Bar() // Call method indicated on the stack with arguments 

又如这样的代码:

new Bar().Foo(); 

编译器生成用于此call指令和不callvirt(这意味着,上this没有空校验)

在其他情况下,则不能确定this不会为空。

无论如何,空检查真的很快。

相关问题