нечетность производительности цикла в .NET x64: сходство с четными числами итераций?

Запустив пустой цикл for с большим количеством итераций, я получаю дико отличающиеся числа от того, сколько времени потребуется для запуска:

public static class Program
{
    static void Main()
    {
        var sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < 1000000000; ++i)
        {
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

Вышеуказанное будет работать на моей машине примерно через 200 мс, но если я увеличу его до 1000000001, то потребуется4x как долго! Тогда, если я сделаю это 1000000002, то снова снизится до 200мс!

Этоткажется произойти за четное количество итераций. Если я пойдуfor (var i = 1; i < 1000000001, (обратите внимание, начиная с 1 вместо 0), то это 200 мс. Или если я сделаюi <= 1000000001 (обратите внимание, меньше, чемили равно) тогда это 200мс. Или же(var i = 0; i < 2000000000; i += 2) также.

Это, кажется, только на x64, но на всех версиях .NET до (по крайней мере) 4.0. Также он появляется только в режиме релиза с отключенным отладчиком.

ОБНОВИТЬ Я думал, что это, вероятно, из-за некоторого умного сдвига битов в jit, но следующее, кажется, опровергает это: если вы делаете что-то вроде создания объекта внутри этого цикла, тоэто занимает около 4х раз:

public static class Program
{
    static void Main()
    {
        var sw = new Stopwatch();
        sw.Start();
        object o = null;
        for (var i = 0; i < 1000000000; i++)
        {
            o = new object();
        }
        sw.Stop();
        Console.WriteLine(o); // use o so the compiler won't optimize it out
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

На моей машине это занимает около 1 секунды, но затем увеличивается на 1 до 1000000001.4 секунды, Это дополнительные 3000 мс, так что на самом деле это не может быть связано со смещением битов, поскольку это также показало бы разницу в 3000 мс в исходной задаче.

Ответы на вопрос(1)

Ваш ответ на вопрос