Ohne Optimierungen erzeugt der Compiler sehr dummen Code - jeder Befehl wird auf sehr einfache Weise kompiliert, so dass er das beabsichtigte tut. In den Debug-Builds sind Optimierungen standardmäßig deaktiviert, da die erstellte ausführbare Datei ohne die Optimierungen auf einfache Weise mit dem Quellcode übereinstimmt.
In Registern gespeicherte Variablen
Sobald Sie die Optimierungen aktiviert haben, wendet der Compiler viele verschiedene Techniken an, um den Code schneller auszuführen, während Sie immer noch dasselbe tun. Der offensichtlichste Unterschied zwischen optimierten und nicht optimierten Builds in Visual C ++ besteht darin, dass die Variablenwerte in optimierten Builds so lange wie möglich in Registern gespeichert werden, während sie ohne Optimierungen immer im Speicher gespeichert werden. Dies wirkt sich nicht nur auf die Codegeschwindigkeit aus, sondern auch auf das Debuggen. Aufgrund dieser Optimierung kann der Debugger beim Durchlaufen des Codes keinen zuverlässigen Variablenwert erhalten.
Andere Optimierungen
Der Compiler wendet mehrere andere Optimierungen an, wie in den MSDN-Dokumenten zu / O-Optionen (Code optimieren) beschrieben . Eine allgemeine Beschreibung verschiedener Optimierungstechniken finden Sie im Wikipedia Compiler Optimization-Artikel .
Aus Paul Vicks Blog:
Es werden alle NOP-Anweisungen entfernt, die wir sonst zur Unterstützung des Debuggens ausgeben würden. Wenn die Optimierungen deaktiviert sind (und die Debugging-Informationen aktiviert sind), gibt der Compiler NOP-Anweisungen für Zeilen aus, denen keine tatsächliche IL zugeordnet ist, für die Sie jedoch möglicherweise einen Haltepunkt festlegen möchten. Das häufigste Beispiel für so etwas ist das "End If" einer "If" -Anweisung - es wird keine tatsächliche IL für ein End If ausgegeben, sodass wir kein NOP ausgeben. Der Debugger lässt Sie keinen Haltepunkt setzen darauf. Durch das Aktivieren von Optimierungen wird der Compiler gezwungen, die NOPs nicht auszugeben.
Wir führen eine einfache grundlegende Blockanalyse der generierten IL durch, um alle toten Codeblöcke zu entfernen. Das heißt, wir teilen jede Methode in IL-Blöcke auf, die durch Verzweigungsbefehle getrennt sind. Durch eine schnelle Analyse der Wechselbeziehung der Blöcke können wir alle Blöcke identifizieren, die keine Verzweigungen aufweisen. Auf diese Weise können wir Codeblöcke herausfinden, die niemals ausgeführt werden und weggelassen werden können, wodurch die Assembly etwas kleiner wird. An dieser Stelle führen wir auch einige kleinere Verzweigungsoptimierungen durch. Wenn Sie beispielsweise eine andere GoTo-Anweisung verwenden, optimieren wir nur die erste GoTo, um zum Ziel der zweiten GoTo zu springen.
Wir geben ein DebuggableAttribute mit IsJITOptimizerDisabled auf False aus. Grundsätzlich ermöglicht dies der Laufzeit-JIT, den Code nach eigenem Ermessen zu optimieren, einschließlich Neuordnung und Inlining von Code. Dies führt zu effizienterem und kleinerem Code, bedeutet jedoch, dass der Versuch, den Code zu debuggen, sehr schwierig sein kann (wie jeder, der ihn ausprobiert hat, Ihnen sagen wird). Die tatsächliche Liste der JIT-Optimierungen ist etwas, das ich nicht kenne - vielleicht mischt sich irgendwann jemand wie Chris Brumme ein. Das lange und das kurze daran ist, dass der Optimierungsschalter Optimierungen ermöglicht, die das Setzen von Haltepunkten und das Durchlaufen Ihres Codes erschweren können.
quelle
Die kurze Antwort lautet: Verwenden Sie -Ox und lassen Sie den Compiler seine Arbeit erledigen.
Die lange Antwort: Der Effekt verschiedener Arten von Optimierungen ist unmöglich genau vorherzusagen. Manchmal führt die Optimierung für schnellen Code tatsächlich zu kleinerem Code als bei der Optimierung für die Größe. Wenn Sie wirklich die letzten 0,01% der Leistung (Geschwindigkeit oder Größe) erzielen möchten, müssen Sie verschiedene Kombinationen von Optionen vergleichen.
Neuere Versionen von Visual Studio bieten außerdem Optionen für erweiterte Optimierungen wie die Optimierung der Verbindungszeit und die profilgesteuerte Optimierung.
quelle