我刚读了Eric Lippert的一篇文章http://ericlippert.com/2009/03/06/locks-and-exceptions-do-not-mix/
对于以下代码,他提到编译器可以在监视器输入和尝试保护区域之间生成无操作指令:
var temp = obj;
Monitor.Enter(temp);
try { body }
finally { Monitor.Exit(temp); }
为什么编译器会在那里生成一个nop?
答案 0 :(得分:3)
这是传统x64抖动的问题。它使用NOP指令来对齐代码。对齐代码是一种优化策略,它使分支预测器更有效,并减少指令解码器必须做的工作才能到达分支目标。您可以在标题为" Intel 64和IA-32的英特尔处理器手册中看到这一点 架构 优化参考手册"第3.4.1.5章:
汇编/编译器编码规则12.(M影响,H一般性)所有分支 目标应该是16字节对齐。
可悲的是,这些NOP现在是Thread.Abort()的可能目标,允许在到达try / finally块之前中止线程。由于不愉快的结果,锁将被采取但不释放。这种情况发生的可能性非常低,而不是零。
这不是完整的故事,因为它只是抖动中的一个普通错误,因为try块在实践中不是分支目标。传统的x64抖动团队还有其他一些棘手的问题,看起来他们的成员在工作完成后分散,并且已知错误没有得到修复。微软创建了一个新的团队,他们重写了抖动,项目名称RyuJIT,自.NET 4.6起可用。他们放弃了x64代码库,并使用x86抖动代码库作为起点。
答案 1 :(得分:0)
nop指令用于在非优化构建中放置断点。
当我们运行非优化构建时,nop指令仅在调试模式下生成,如果我们使用优化标志构建项目,那么这些指令将不在生成的IL中。