2015-06-30 9 views
9

Ich bin neu in C# und habe ein Problem mit dem folgenden Code (ich habe das Ziel-Framework als 4.5 und ich habe hinzugefügt ein Verweis auf System.Numerics):C# 64-Bit-Release-Build gestartet ohne Debugging verhält sich anders als beim Debuggen gestartet (BigInteger)

using System; 
using System.Numerics; 

namespace Test 
{ 
    class Program 
    { 
     static BigInteger Gcd(BigInteger x, BigInteger y) 
     { 
      Console.WriteLine("GCD {0}, {1}", x, y); 
      if (x < y) return Gcd(y, x); 
      if (x % y == 0) return y; 
      return Gcd(y, x % y); 
     } 

     static void Main(string[] args) 
     { 
      BigInteger a = 13394673; 
      BigInteger b = 53578691; 
      Gcd(a, b); 
     } 
    } 
} 

Wenn das Release-Build mit Debugging (F5 in Visual Studio gestartet wird - und ein Break-Punkt am Ende des Programms, so kann ich die Ausgabe) zu sehen, die ich die Folgende Ausgabe:

GCD 13394673, 53578691 
GCD 53578691, 13394673 
GCD 13394673, 13394672 
GCD 13394672, 1 

Allerdings, wenn der Release-Build ohne Debug gestartet wird Ging (Ctrl-F5), erhalte ich folgendes:

GCD 13394673, 53578691 
GCD 53578691, 53578691 

Merkwürdig, wenn ich eine Console.ReadLine() am Ende des Programms fügen Sie es wie erwartet funktioniert!

Irgendwelche Ideen, was das verursacht? Vielen Dank.

+3

Willkommen zu einem [Heisenbug] (https://en.wikipedia.org/wiki/Heisenbug) –

+0

Hmm ... Ich kann das nicht in VS2015 reproduzieren - ich sehe die erste Ausgabe in beiden Fällen. –

+0

LINQPad verhält sich auf die gleiche Weise - abhängig davon, ob Sie die Optimierung aktivieren oder deaktivieren. Interessant. (Running on Win 7, .NET 4.5.1) – germi

Antwort

11

Dies ist ein x64 Jitter Optimierer Fehler in .NET 4.0 bis 4.5.2. Es ist ziemlich schwierig zu charakterisieren, der Codegen ist aufgrund der Verwendung von BigInteger ziemlich schwer. Der x64-Jitter hatte eine Geschichte von Optimierungsfehlern für struct Typen, wie BigInteger, also ist das die wahrscheinliche Ursache. Die Kombination mit der möglichen Tail-Call-Optimierung in dieser Methode ist der wahrscheinlichste Auslöser.

Ich würde normalerweise empfehlen, einen solchen Fehler zu melden, aber die Tage dieses Jitters sind nummeriert. Microsoft entschied, es in Rente zu gehen und es komplett neu zu schreiben. Verfügbar in .NET 4.6 - VS2015 war der Projektcodename RyuJIT. Es hat diesen Fehler nicht.

Mehrere mögliche Abhilfen:

Project + Eigenschaften, Build Registerkarte Platform target = x86. Dies zwingt das Programm dazu, im 32-Bit-Modus zu laufen und den x86-Jitter zu verwenden, es hat diesen Fehler nicht.

oder deaktivieren Optimierung für diese Methode mit einem Attribut:

using System.Runtime.CompilerServices; 
    ... 
    [MethodImpl(MethodImplOptions.NoOptimization)] 
    static BigInteger Gcd(BigInteger x, BigInteger y) { 
     // etc... 
    } 

was in Ordnung ist, ist das Heben schwerer Lasten in die BigInteger Klasse so die Optimierung deaktivieren nicht die Ausführungszeit beeinflussen würde.

+0

@HansPassant, okay Ich hatte Ziel auf eine beliebige CPU und bevorzugte 32bit, so konnte ich den Fehler nicht reproduzieren. änderte das Ziel und reproduzierte den Fehler. Aber es wurde immer noch nur mit VS2013 und nicht VS2012 reproduziert. –

+0

@HansPassant Ich bin sehr neu in C#, daher ist es ein bisschen enttäuschend, auf einen Bug wie diesen zu stoßen (zumindest war es nicht intermittierend) - würdest du sagen, dass C# im Vergleich zu C++ "fehlerhaft" war? –

+1

Hehe, ja, du hast Pech :) Neuling Programmierer haben ein Talent dafür, niemand schreibt Code wie diesen. Beachten Sie, dass diese Art von Code auch leicht mit dem Namen dieser Site abstürzt, die Nummern groß genug macht und Sie bei einer StackOverflowException umfallen. Welches ist kein Fehler. C++ Compiler haben auch viele Bugs, C# hält sich generell gut. Der Jitter-Optimierer wurde in C++ geschrieben: –