Frage

In den meisten C oder C ++ Umgebungen, gibt es eine "Debug" -Modus und einen "Release" -Modus Kompilation.
Mit Blick auf den Unterschied zwischen den beiden, finden Sie, dass der Debug-Modus die Debug-Symbole (oft die Option -g auf viele Compiler) fügt hinzu, aber es sperrt auch die meisten Optimierungen.
In „Release“ Modus haben Sie in der Regel alle möglichen Optimierungen eingeschaltet.
Warum der Unterschied?

War es hilfreich?

Lösung

Ohne Optimierung auf, ist die Strömung durch den Code linear. Wenn Sie in Zeile 5 und Schritt sind, treten Sie 6. Optimierung der Leitung, können Sie Anweisung Nachbestellung, Schleifenentrollen und alle möglichen Optimierungen erhalten.
Zum Beispiel:


void foo() {
1:  int i;
2:  for(i = 0; i < 2; )
3:    i++;
4:  return;

In diesem Beispiel ohne Optimierung, Sie Schritt durch den Code könnte und treffen Linien 1, 2, 3, 2, 3, 2, 4

Mit Optimierung auf, könnten Sie einen Ausführungspfad erhalten, die wie folgt aussieht: 2, 3, 3, 4 oder sogar nur 4! (Die Funktion tut nichts, nachdem alle ...)

Unterm Strich Debugging-Code mit Optimierung ein königlicher Schmerz aktiviert können! Vor allem, wenn Sie große Funktionen.

Beachten Sie, dass bei der Optimierung Drehen Sie den Code ändert! In bestimmten Umgebung (sicherheitskritische Systeme), ist dies nicht akzeptabel und der Code gedebuggt der Code ausgeliefert werden. Muss ich debuggen mit Optimierung auf in diesem Fall.

Während die optimierte und nicht optimierte Code sollte „funktionell“ gleichwertig unter Umständen sein, wird das Verhalten ändern.
Hier ist ein einfaches Beispiel:

    int* ptr = 0xdeadbeef;  // some address to memory-mapped I/O device
    *ptr = 0;   // setup hardware device
    while(*ptr == 1) {    // loop until hardware device is done
       // do something
    }

Mit Optimierung off, das ist einfach, und man irgendwie wissen, was zu erwarten ist. Wenn Sie jedoch Optimierung einschalten, ein paar Dinge passieren könnte:

  • Der Compiler kann die während der Block optimieren weg (wir init 0 ist, wird es nie 1 sein)
  • Statt Speicher zugreifen, Zeigerzugriff könnte auf eine Register-> No I / O-Update
  • Speicherzugriff kann zwischengespeichert werden (nicht unbedingt Compiler-Optimierung bezogen)

In all diesen Fällen wäre das Verhalten drastisch unterschiedlich und höchstwahrscheinlich falsch.

Andere Tipps

Ein weiterer entscheidender Unterschied zwischen Debug- und Release ist, wie lokale Variablen gespeichert sind. Konzeptionell lokale Variablen zugewiesen Speicherung in einer Frame-Funktionen stapeln. Die Symboldatei vom Compiler erzeugten teilt den Debugger des Offset der Variablen in dem Stapelrahmen, so dass der Debugger es Ihnen zeigen kann. Der Debugger Peeks an der Speicherstelle, dies zu tun.

Das bedeutet aber, jedes Mal, wenn eine lokale Variable den generierten Code für die Source-Leitung geändert wird, den Wert wieder an die richtige Stelle auf dem Stack zu schreiben. Dies ist sehr ineffizient aufgrund des Speicher-Overhead.

in einer Freigabe build kann der Compiler eine lokale Variable in ein Register für einen Teil einer Funktion zuweisen. In einigen Fällen kann es nicht Stapelspeicher für sie auf allen (je mehr Registern eine Maschine hat, desto leichter, dies zu tun ist).

assign

Allerdings ist der Debugger weiß nicht, wie Karte für einen bestimmten Punkt auf lokale Variablen registriert im Code (Ich bin nicht bekannt, dass Symbolformat, das diese Informationen enthält), so kann es es Ihnen nicht genau zeigen, da sie nicht, wohin sie gehen nicht kennt, es zu suchen.

Eine weitere Optimierung würde Funktion inlining sein. In optimierten baut der Compiler einen Aufruf ersetzen kann für foo () mit dem eigentlichen Code foo überall es wird verwendet, weil die Funktion klein genug ist. Wenn Sie jedoch versuchen, einen Haltepunkt auf foo () gesetzt der Debugger will die Adresse der Anweisungen für foo () kennen zu lernen, und es ist nicht mehr eine einfache Antwort auf diese Frage - es kann Tausende von Kopien der foo ( ) Code-Bytes über das Programm zu verbreiten. Ein Debug-Build wird gewährleistet, dass es irgendwo für Sie den Haltepunkt zu setzen.

Code Optimierung ist ein automatisierter Prozess, der die Laufzeit-Performance des Codes verbessert, während Semantik zu erhalten. Dieser Prozess kann Zwischenergebnisse zu entfernen, die sind unncessary einen Ausdruck oder eine Funktion Auswertung abgeschlossen ist, kann aber für Sie von Interesse sein, wenn das Debuggen. Auf ähnliche Weise können Optimierungen, den scheinbaren Steuerfluss verändern, so dass die Dinge in einer etwas anderen Reihenfolge passieren können, als das, was im Quelltext angezeigt. Dies geschieht, um unnötige oder redundante Berechnungen zu überspringen. Dieser rejiggering von Code kann Schlamassel mit der Zuordnung zwischen Quellcodezeilennummern und Objektcode-Adressen macht es schwer für einen Debugger den Ablauf der Steuerung zu folgen, wie Sie es geschrieben haben.

Debuggen in nicht optimierten Modus ermöglicht es Ihnen, alles zu sehen, die Sie geschrieben haben, wie Sie es ohne das Optimierungsprogramm geschrieben haben, zu entfernen oder Neuordnen Dinge.

Wenn Sie sind glücklich, dass Ihr Programm korrekt funktioniert können Sie auf Optimierungen drehen verbesserte Leistung zu erhalten. Obwohl Optimizern ziemlich vertrauenswürdig in diesen Tagen, es ist immer noch eine gute Idee, um eine gute Qualität Test-Suite zu bauen, um sicherzustellen, dass Ihr Programm identisch läuft (aus funktionaler Sicht, ohne Berücksichtigung von Leistung) sowohl in optimierte und nicht optimiert Modus.

Die Erwartung ist, dass die Debug-Version werden - ausgetestet! Haltepunkte setzen, Einzelschritt während Variablen, Stack-Traces zu beobachten, und alles, was Sie in einem Debugger tun (IDE oder aus anderen Gründen) Sinn machen, wenn jede Zeile nicht leer ist, nicht-Kommentar Quellcode einige Maschinencodebefehle übereinstimmt.

Die meisten Optimierungen Chaos mit der Reihenfolge des Maschinencodes. Schleifenentrollen ist ein gutes Beispiel. Gemeinsame Unterausdrücke kann aus Schlingen angehoben werden. Mit Optimierung eingeschaltet, auch die einfachsten Ebene kann versuchen Sie einen Haltepunkt auf einer Linie zu setzen, die auf der Ebene Maschinencode, existiert nicht. Irgendwann kann man nicht eine lokale Variable überwacht aufgrund es in einem CPU-Register gehalten wird, oder vielleicht sogar aus der Existenz optimierte!

Wenn Sie auf der Befehlsebene Debuggen sind eher als das Source-Level, dann ist es eine sehr viel einfacher für Sie nicht optimieren Anweisungen an die Quelle zurück zur Karte. Auch Compiler werden gelegentlich in ihren Optimizern Buggy.

In der Windows-Division bei Microsoft, alle Release-Binärdateien mit Debugging-Symbolen und voller Optimierungen gebaut. Die Symbole werden in separaten PDB-Dateien gespeichert und nicht die Leistung des Codes beeinflussen. Sie haben nicht mit dem Produkt versenden, aber die meisten von ihnen sind unter Microsoft Symbol Server .

Ein weiteres der Probleme mit Optimierungen sind Inline-Funktionen, auch in dem Sinne, dass Sie immer einstufiges durch sie.

Mit GCC, mit Debugging und Optimierungen aktiviert zusammen, wenn Sie nicht wissen, was Sie erwarten wird denken, dass der Code misbehaving und erneute Ausführung der gleichen Anweisung mehrmals - es zu ein paar meiner Kollegen passiert ist. Auch Informationen von GCC mit Optimierungen auf neigen gegeben Debuggen von schlechterer Qualität sein, als sie könnten, tatsächlich.

jedoch in Sprachen, die von einer virtuellen Maschine wie Java gehostet, Optimierungen und Fehlersuche koexistieren können - auch während des Debuggen, JIT-Kompilierung zu nativen Code weiter, und nur der Code debuggt Methoden transparent zu einer nicht optimierten Version umgewandelt wird

Ich möchte, dass die Optimierung betonen, sollte das Verhalten des Codes nicht ändern, es sei denn, der verwendete Optimierer Buggy ist, oder der Code selbst ist fehlerhaft und stützt sich auf teilweise undefiniert Semantik; letztere ist häufiger bei multithreaded Programmierung oder beim Inline-Montage wird auch verwendet.

  

Code mit Debug-Symbole sind größer, die mehr Cache-Misses bedeuten kann, das heißt langsamer, was ein Problem für Server-Software sein kann.

Mindestens auf Linux (und es gibt keinen Grund, warum Windows-anders sein sollte) Debug-Informationen werden in einem separaten Abschnitt der binären verpackt und werden nicht während der normalen Ausführung geladen. Sie können in einer anderen Datei aufgeteilt werden für die Fehlersuche verwendet werden. Auch auf einigen Compilern (einschließlich Gcc, ich denke, auch mit Microsofts C-Compiler) Debugging-Informationen und Optimierungen können sowohl aktiviert zusammen. Wenn nicht, offensichtlich ist der Code geht langsamer sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top