以下代码的结果不同如果在后台启动调试器或没有调试器。如果优化已经开启,那么差异就在那里。
结果如下:
- >与优化: 1000 2008年 3016 1001 2009年 3007 ...
- >没有优化(如预期的那样) 1000 1008 1016 1001 1009 1017 ...
代码:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace OptimizerTest
{
public class Test
{
int dummy;
public void TestFunction(int stepWidth)
// stepWidth must be a parameter
{
for (int step = 0; step < stepWidth; step++)
{
dummy = step + 1000;
// addition with constant ( same value as later !)
for (int x = 0; x < 20; x += stepWidth)
{
int index = x + 1000 + step;
// constant must be same as above and ?!?!
// int index = x + step + 1000; works !!!!!
Console.Write("\n\r" + index);
}
}
}
[MethodImpl(MethodImplOptions.NoOptimization)]
public void TestFunctionNoOptimization(int stepWidth)
{
for (int step = 0; step < stepWidth; step++)
{
dummy = step + 1000;
for (int x = 0; x < 20; x += stepWidth)
{
int index = x + 1000 + step;
Console.Write("\n\r" + index);
}
}
}
}
class Program
{
/// <summary>
/// Result differs from Start with F5 to Ctrl-F5
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Test test = new Test();
Console.Write("\n\r---------\n\roptimized result\n\r-------------" );
test.TestFunction(8);
Console.Write("\n\r---------\n\rnot optimized result\n\r-------------");
test.TestFunctionNoOptimization(8);
Console.Write("\n\r---------\n\rpress any key");
Console.ReadKey();
}
}
}
错误的行为取决于内循环的迭代次数(x <5,一切正常)。非常有趣的是,当我使用
时不会发生 int index = x + step + 1000;
而不是
int index = x + 1000 + step;
我正在使用Visual Studio 2010 SP1并尝试使用.NET Framework从2.0到4.0.3。我总是看到同样的结果。
有人知道这个错误还是可以重现?
答案 0 :(得分:20)
是的,这绝对是一个抖动优化器错误。其他SO用户重现它的原因是因为只有x64抖动似乎有这个bug。您必须将项目的平台目标设置为AnyCPU,取消VS2012上的“首选32位”选项以及更新。
我没有仔细研究潜在的原因,但似乎在尝试消除常见的step + 1000
子表达式时摸索。子表达式消除是标准抖动优化之一。但是它错误地将表达式代码合并到循环中,而不是像写入的那样将它保持在循环之外。例如,当您写下来时,您会看到错误消失:
dummy = step + 999;
最新的.NET 4.5.1版本(我机器上的clrjit.dll,v4.0.30319.34003)中仍然存在此错误,同样存在于v2抖动中(mscorjit.dll,v2.0.50727.7905)机)。
代码有点过于合成,无法推荐一个可靠的解决方法,你已经找到了一个,所以你可以继续驾驶你的项目。一般来说,我建议您使用以下方法消除子表达式:
int index = x + dummy;
应该向Microsoft报告,您可以通过在connect.microsoft.com上发布错误报告来实现。如果你不想花时间让我知道,我会照顾它。