In meinem Delphi7 ist dieser Code
%Vor%erzeugt eine AV: Zugriffsverletzung bei der Adresse 0041D6D1 im Modul 'Project1.exe'. Lesen der Adresse 00000000. Aber jemand besteht darauf, dass es keine Ausnahme machen sollte, egal was passiert. Er sagt auch, dass sein Delphi 5 tatsächlich keine Ausnahmen macht. Er nennt dies einen "abgestandenen Zeiger Bug". Mit anderen Worten sagt er, dass FreeAndNil nicht als Debugger verwendet werden kann, um einen doppelten Versuch zu erkennen, ein Objekt freizugeben oder ein freigegebenes Objekt zu verwenden.
Kann mich jemand aufklären? Sollte dieser Raise und Fehler (immer / zufällig) oder das Programm diesen Bug ohne Probleme durchlaufen?
Danke
Ich frage das, weil ich glaube, dass ich in meinem Programm einen "doppelten freien Gegenstand" oder "freien und Wiederzugriff" -Bug habe. Wie kann ich den Speicher, der einem Objekt zugewiesen ist, mit Nullen füllen, NACHDEM ich das Objekt freigegeben habe? Ich möchte auf diese Weise erkennen, wo der Fehler liegt, indem ich AV bekomme. Anfangs hoffte ich, dass ich, wenn ich das Objekt auf FreeAndNil setze, IMMER einen AV bekommen werde, wenn ich versuche, wieder darauf zuzugreifen.
Es ist immer falsch, Methoden oder Eigenschaften eines Nullverweises zu verwenden, auch wenn es manchmal scheint, dass es funktioniert.
FreeAndNil
kann tatsächlich nicht verwendet werden, um doppelte Frees zu erkennen. Es ist sicher, FreeAndNil
für eine Variable namens night-nil aufzurufen. Da es sicher ist, hilft es Ihnen nichts zu erkennen.
Dies ist kein veralteter Pointer-Bug. Dies ist ein Null-Referenz-Fehler. Ein Veraltete-Zeiger-Fehler tritt auf, wenn Sie ein Objekt freigegeben haben, aber nicht alle Variablen gelöscht hat, auf die verwiesen wurde. Dann enthält die Variable immer noch die alte Adresse des Objekts. Diese sind sehr schwer zu erkennen. Sie können einen solchen Fehler erhalten:
%Vor%Sie können auch eine solche erhalten:
%Vor% Die Verwendung von MStr.Size
, nachdem Sie das Objekt MStr
referenziert haben, ist ein Fehler und sollte eine Ausnahme auslösen. Ob eine Ausnahme auslöst, hängt von der Implementierung ab. Vielleicht wird es das und vielleicht auch nicht. Es ist jedoch nicht zufällig.
Wenn Sie nach einem doppelt-freien Fehler suchen, können Sie die von FastMM bereitgestellten Debug-Hilfsprogramme verwenden, wie auch andere vorgeschlagen haben. Es funktioniert, indem es den Speicher tatsächlich nicht zurück an das Betriebssystem oder sogar zurück an den internen Freispeicherpool von Delphi freigibt. Stattdessen werden bekannte Daten in den Speicherbereich des Objekts geschrieben. Wenn Sie diese Werte sehen, wissen Sie, dass Sie etwas lesen, das Sie bereits freigegeben haben. Außerdem wird die VMT des Objekts geändert, sodass Sie beim nächsten Aufruf einer virtuellen Methode für diese Objektreferenz eine vorhersehbare Ausnahme erhalten und Ihnen sogar mitteilen können, welches vermeintlich freigegebene Objekt Sie verwenden wollten. Wenn Sie versuchen, das Objekt erneut freizugeben, kann es Ihnen nicht nur mitteilen, dass Sie es bereits freigegeben haben, sondern auch, wo es beim ersten Mal (mit einem Stack-Trace) freigegeben wurde und wo es zugewiesen wurde. Es sammelt auch diese Informationen, um über Speicherlecks zu berichten, bei denen Sie ein Objekt weniger als einmal statt mehr freigegeben haben.
Es gibt auch Gewohnheiten, die Sie verwenden können, um das Problem für zukünftigen Code zu vermeiden:
FreeAndNil
für seine Variable aufruft, bleibt die Variable des anderen Codes unverändert. Wenn der andere Code denkt, dass er das Objekt besitzt, dann sind Sie in Schwierigkeiten. (Dieses Konzept des Besitzers ist nicht notwendigerweise mit der Eigenschaft TComponent.Owner
verbunden. Es muss kein Objekt sein , das es besitzt; es könnte ein allgemeines Subsystem Ihres Programms sein.) Nur um das Problem zu verkomplizieren:
Wenn die Methode, die Sie aufrufen, eine statische (nicht virtuelle) Methode ist und keine virtuellen Methoden selbst aufruft oder auf Felder des Objekts zugreift, erhalten Sie auch dann keine Zugriffsverletzung, wenn die Objektreferenz gesetzt wurde zu NIL.
Der Grund dafür ist, dass die Zugriffsverletzung durch Dereferenzieren des Selbstzeigers (in diesem Fall NIL) verursacht wird, aber nur beim Zugriff auf ein Feld oder die VMT des Objekts zum Aufruf einer virtuellen Methode.
Dies ist nur eine Ausnahme von der Regel, dass Sie Methoden eines NIL-Objektverweises, die ich hier erwähnen möchte, nicht aufrufen können.
Wenn Sie einen Zeiger auf Null setzen, sollten Sie ihn nicht mehr verwenden können. Aber wenn Sie einen anderen Zeiger auf das gleiche Objekt haben, können Sie es verwenden, ohne ein AV zu bekommen, weil dieser Zeiger immer noch auf die Objektadresse zeigt und nicht auf Null.
Darüber hinaus wird durch das Freigeben eines Objekts der vom Objekt verwendete Speicher nicht gelöscht. Es markiert nur, dass es nicht verwendet wird. Das ist der Grund, warum Sie ein AV bekommen möchten. Wenn der freigegebene Speicher für ein anderes Objekt reserviert wird, erhalten Sie ein AV, weil es keine Daten mehr enthält, die gültig scheinen.
FastMM4 verfügt über einige Einstellungen, die Sie beim Debuggen verwenden können, um solche Bedingungen zu erkennen. Von der FsatMM4Options.inc:
{Legen Sie die folgende Option fest, um eine umfassende Überprüfung aller Speicherblöcke durchzuführen. Alle Blöcke werden sowohl mit einem Header als auch mit einem Trailer aufgefüllt, die zur Überprüfung der Integrität des Heaps. Freed Blöcke sind auch gelöscht, um sicherzustellen, dass sie kann nach der Freigabe nicht wiederverwendet werden. Diese Option verlangsamt Speichervorgänge dramatisch und sollte nur verwendet werden, um eine Anwendung zu debuggen, die ist Überschreiben von Speicher oder Wiederverwenden von freigegebenen Zeigern. Einstellung dieser Option aktiviert automatisch CheckHeapForCorruption und deaktiviert ASMVersion. Sehr wichtig: Wenn Sie diese Option aktivieren, benötigt Ihre Anwendung die FastMM_FullDebugMode.dll-Bibliothek. Wenn diese Bibliothek nicht verfügbar ist, werden Sie beim Start einen Fehler bekommen.}
{$ definiere FullDebugMode}
Noch ein Zitat aus der gleichen Datei:
FastMM fängt immer Versuche auf, denselben Speicherblock zweimal zu löschen ...
Da Delphi FastMM von Delphi 2007 (2006?) verwendet, sollten Sie einen Fehler erhalten, wenn Sie versuchen, ein Objekt doppelt zu laden.
Thomas Müller : Haben Sie virtuelle Klassenmethoden ausprobiert? Ein Konstruktor ist eine Art virtuelle Methode, aber Sie nennen sie gegen den Typ - nicht die Instanz. Dies bedeutet, dass selbst einige spezifische virtuelle Methoden nicht zu einer Nullreferenz von AV führen: D
Vegar : Du könntest nicht richtiger sein! FastMM ist das beste Werkzeug aller Zeiten, das mir geholfen hat, diese Art von Bugs aufzuspüren.
Der EurekaLog Blog hatte im April 2009 einen großartigen Beitrag hierzu:
Warum sollten Sie immer FreeAndNil anstelle von Free verwenden?
Tags und Links delphi