dziwność wydajności dla pętli w .NET x64: powinowactwo do liczby iteracji parzystej?

Uruchamiając pustą pętlę for-loop z dużą liczbą iteracji, otrzymuję bardzo różne liczby w czasie trwania:

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);
    }
}

Powyższe uruchomi się około 200ms na moim komputerze, ale jeśli zwiększę go do 1000000001, to zajmie4x jak długo! Potem, jeśli zrobię to 1000000002, to znowu spadnie do 200ms!

Towydaje się zdarzyć się na parzystą liczbę iteracji. Jeśli pójdęfor (var i = 1; i < 1000000001, (uwaga zaczynając od 1 zamiast 0) to 200ms. Albo jeśli to zrobięi <= 1000000001 (zanotuj mniej niżlub równe) to 200ms. Lub(var i = 0; i < 2000000000; i += 2) także.

To wydaje się być tylko na x64, ale we wszystkich wersjach .NET do (przynajmniej) 4.0. Również pojawia się tylko w trybie zwolnienia z odłączonym debuggerem.

AKTUALIZACJA Myślałem, że to prawdopodobnie z powodu jakiegoś sprytnego przesunięcia bitowego w jicie, ale poniższe zdaje się obalać to: jeśli zrobisz coś takiego jak stworzenie obiektu wewnątrz tej pętli, toże trwa około 4 razy dłużej:

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);
    }
}

Zajmuje to około 1 sekundy na moim komputerze, ale następnie zwiększa się o 1 do 10000000014 sekundy. To dodatkowe 3000 ms, więc nie mogło być tak naprawdę z powodu przesunięcia bitów, ponieważ pokazałoby to również różnicę 3000 ms w pierwotnym problemie.

questionAnswers(1)

yourAnswerToTheQuestion