Memory Leak mit Intel Compiler, mit GCC aber nicht...
-
wie hast du da jetzt rausgefunden, dass hier ein memory leak ist?
-
Ist der gepostete Codeschnippsel teil der Klasse?
Ganz wichtig ist die Frage: in welchem Scope ist die Instanz der Klasse deklariert, die besagtes vPoints enthaelt? Ist es eine globale Variable? Oder eine statische? Falls ja, dann hast du deine Antwort.
Und nach der statischen Deklaration in "class derive", löscht sich vPoints nach dem Aufruf des Destruktors doch von selbst, oder nicht ?
Was ist eine statische Deklaration?

class caeTokenizer split(input,*cToken);hier das "class"-Keyword zu verwenden ist uebrigens strange, IMHO

-
und schrieb:
wie hast du da jetzt rausgefunden, dass hier ein memory leak ist?
Indem ich eine for-Schleife (i z.B. bis 10000) um das Hauptprogramm gelegt habe, Teilelemente innerhalb des Hauptprogramms auskommentiert und immer tiefer in die Hierachie der Funktionsaufrufe heruntergearbeitet habe, bis ich das Memory Leak durch eine simple Zeile detektiert wurde, d.h. jedes Mal Programm kompiliert, ausgeführt und im Task-Manager beobachtet. Steigt der Speicher = Loch, bleibt der Speicherverbrauch konstant = kein Loch.
Blue-Tiger schrieb:
Ist der gepostete Codeschnippsel teil der Klasse?
ja
Blue-Tiger schrieb:
Und nach der statischen Deklaration in "class derive", löscht sich vPoints nach dem Aufruf des Destruktors doch von selbst, oder nicht ?
Was ist eine statische Deklaration ?Meine Formulierungen sind vielleicht nicht immer "fachmännisch" ^^, ich meine damit..
// dynamisch oder Block-Resistent { double *ptr = new double[10]; . . } // ->> ptr überlebt den "Block", Speicherbereich bleibt reserviert // statisch oder Block-Flüchtig { double array[10]; . . } // ->> der Speicherbereich von array wird nach Ende des Blocks automatisch freigegeben. // Ebenfalls statisch nach meiner Vorstellung class abstract { public: abstract(); ~abstract(); . . }; class derive:public abstract { public: derive(); virtual ~derive(); private: std::vector<double> vPoints; // <<-- ebenfalls Block-Flüchtig, wird nach Ende des Objektes automatisch freigegeben }
-
// dynamisch oder Block-Resistent { double *ptr = new double[10]; . . } // ->> ptr überlebt den "Block", Speicherbereich bleibt reserviertSo nicht ganz richtig. ptr wird nach dem Block nicht mehr geben, aber das Double[10] bleibt auf dem Heap. Kann aber nicht mehr gelöscht werden, weil es kein Zeiger mehr gibt. Memory Leak!!!
-
Winn schrieb:
und schrieb:
wie hast du da jetzt rausgefunden, dass hier ein memory leak ist?
Indem ich eine for-Schleife (i z.B. bis 10000) um das Hauptprogramm gelegt habe, Teilelemente innerhalb des Hauptprogramms auskommentiert und immer tiefer in die Hierachie der Funktionsaufrufe heruntergearbeitet habe, bis ich das Memory Leak durch eine simple Zeile detektiert wurde, d.h. jedes Mal Programm kompiliert, ausgeführt und im Task-Manager beobachtet. Steigt der Speicher = Loch, bleibt der Speicherverbrauch konstant = kein Loch.
[/cpp]Da gibts wesentlich bessere Mittel. In einem anderen Thread wurde die Tage der Link fuer ein Plugin fuer's Visual Studio gepostet, der sowas automatisch macht. Unter Linux hilft dir Valgrind sicher weiter...
Meine Vermutung ist uebrigens, dass du durch das auskommentieren der obgenannten Zeile bewirkt hast, dass der Compiler die ganze Schleife wegoptimiert. Eine einfache Variable in einen std::vector zu pushen kann eigentlich nicht wirklich fuer ein Speicherleck verantwortlich sein. Was macht convertString() denn?
-
@Aprollo:: gg, wenn man es ganz genau nimmt - stimmt das !!

Blue-Tiger schrieb:
Da gibts wesentlich bessere Mittel. In einem anderen Thread wurde die Tage der Link fuer ein Plugin fuer's Visual Studio gepostet, der sowas automatisch macht. Unter Linux hilft dir Valgrind sicher weiter...
Ich arbeite unter Mac OS X - in einer VM habe ich Linux laufen, Valgrind läuft auch schon, aber mit Boost habe ich derzeit meine Probleme... haste Du noch den Namen für das VS .NET Plugin ?
Blue-Tiger schrieb:
Was macht convertString() denn?
convertString wandelt mit Hilfe von istringstream den String in einen Double um (siehe unten). Ich kann mir auch nicht vorstellen, daß eine push_back Aktion ein Leak erzeugt - das mir der Intel Compiler die Schleife wegoptimiert... darüber habe ich noch gar nicht nachgedacht, könnte natürlich sein... macht die Suche dann noch schwerer :S
bool convertString(const std::string &str, double &Val) { std::istringstream tmp(str); if (!(tmp >> Val)) return false; return true; }
-
Winn schrieb:
@Aprollo:: gg, wenn man es ganz genau nimmt - stimmt das !!

Blue-Tiger schrieb:
Da gibts wesentlich bessere Mittel. In einem anderen Thread wurde die Tage der Link fuer ein Plugin fuer's Visual Studio gepostet, der sowas automatisch macht. Unter Linux hilft dir Valgrind sicher weiter...
Ich arbeite unter Mac OS X - in einer VM habe ich Linux laufen, Valgrind läuft auch schon, aber mit Boost habe ich derzeit meine Probleme... haste Du noch den Namen für das VS .NET Plugin ?
IMO ist hier VLD aka Virtual Leak Detector gemeint, allerdings IMO eine Bibliotek(?) und kein Plugin
-
Wie genau verwendest du denn diese Klasse?
ich tippe spontan auf sowas:
abstract* ptr = new derive; for(...) ptr->testleak(); delete ptr;-> und da könnte es Probleme geben, weil der abstact-Dtor nicht virtuell ist (was da passiert, ist undefiniert - meistens beschränkt es sich daraf, daß der Basis-Dtor direkt verwendet wird (und der derive-Teil nicht aufgeräumt wird).
-
CStoll schrieb:
Wie genau verwendest du denn diese Klasse?
ich tippe spontan auf sowas:
abstract* ptr = new derive; for(...) ptr->testleak(); delete ptr;-> und da könnte es Probleme geben, weil der abstact-Dtor nicht virtuell ist (was da passiert, ist undefiniert - meistens beschränkt es sich daraf, daß der Basis-Dtor direkt verwendet wird (und der derive-Teil nicht aufgeräumt wird).
Nein, so verwende ich sie nicht... eher etwa so...
// Einzelobjekt-Erstellung derive *ptr = new derive[1]; ptr->doSomething(); // Einfügung in eine Liste std::vector<class abstract *> ptr_collection; ptr_collection.push_back(derive); // Löschung aller Objekte in der Liste; std::vector<class abstract *>::iterator itObj; for(itObj = ptr_collection.begin(); itObj != ptr_collection.end(); ++itObj) delete[] (*itObj);Könnte es sein, daß wenn ich die Löschung über die <abstract> Klasse vornehme, die Polymorphie nicht per Standard definiert ist... habe gerade gesehen, daß mein <derive> DTOR nicht aufgerufen wird...
-
Winn schrieb:
CStoll schrieb:
Wie genau verwendest du denn diese Klasse?
ich tippe spontan auf sowas:
abstract* ptr = new derive; for(...) ptr->testleak(); delete ptr;-> und da könnte es Probleme geben, weil der abstact-Dtor nicht virtuell ist (was da passiert, ist undefiniert - meistens beschränkt es sich daraf, daß der Basis-Dtor direkt verwendet wird (und der derive-Teil nicht aufgeräumt wird).
Nein, so verwende ich sie nicht... eher etwa so...
[snip]Das ist doch genau so - nur daß es etwas tiefer verborgen ist - du verwendest einen 'abstract*', um darüber 'derive'-Objekte zu löschen.
(btw, Arrays von polymorphen Objekten könnten noch weitere Gefahren mit sich bringen - dadurch, daß abgeleitete Objekte normalerweise größer sind als ihre Basisklasse, stimmt die Pointer-Arithmetik nicht mehr.Könnte es sein, daß wenn ich die Löschung über die <abstract> Klasse vornehme, die Polymorphie nicht per Standard definiert ist... habe gerade gesehen, daß mein <derive> DTOR nicht aufgerufen wird...
Das kann nicht nur sein, das ist so. Und um das zu lösen, muß der Destruktor der Basisklasse virtuell definiert werden.
-
CStoll schrieb:
Könnte es sein, daß wenn ich die Löschung über die <abstract> Klasse vornehme, die Polymorphie nicht per Standard definiert ist... habe gerade gesehen, daß mein <derive> DTOR nicht aufgerufen wird...
Das kann nicht nur sein, das ist so. Und um das zu lösen, muß der Destruktor der Basisklasse virtuell definiert werden.
Klasse, Danke CStoll !! Das wars... welch ein "dämlicher" Fehler... gcc hatte mich wohl verstanden, gg
-
Normalerweise gibst für diese Fehler meistens Compilerwarnung o_O
Hab zwar daran gedacht, aber dachte der Kompiler würde meckern xd
-
nt
-
Aprollo schrieb:
Normalerweise gibst für diese Fehler meistens Compilerwarnung o_O
Hab zwar daran gedacht, aber dachte der Kompiler würde meckern xdNun, weder der Intel noch der GCC haben gemeckert... das liegt wohl daran, daß ich zwar in der Basisklasse ein "virtuell" vor dem Destruktor hatte, aber auch bei der abgeleiteten Basisklasse
Nachdem ich die "virtuell" Deklarationen in den abgeleiteten Destrokturen entfernt hatte, verschwand mein Memory Leak... es war wohl einfach zuviel des Guten :S
-
CStoll schrieb:
Und um das zu lösen, muß der Destruktor der Basisklasse virtuell definiert werden.
Nun, weder der Intel noch der GCC haben gemeckert... das liegt wohl daran, daß ich zwar in der Basisklasse ein "virtuell" vor dem Destruktor hatte, aber auch bei der abgeleiteten Basisklasse
Nachdem ich die "virtuell" Deklarationen in den abgeleiteten Destrokturen entfernt hatte, verschwand mein Memory Leak... es war wohl einfach zuviel des Guten :SWenn in eine Klassen virtuelle Methoden deklariert sind aber keine virtuellen Destuktor, geben Mingw und VC++ Warnungen aus, weil man zwar die Methode richtig dispatchen kann, aber eine delete anweisung nicht.
2 mal virtuelle sollte nicht der Fehler sein o_O
-
Winn schrieb:
Aprollo schrieb:
Normalerweise gibst für diese Fehler meistens Compilerwarnung o_O
Hab zwar daran gedacht, aber dachte der Kompiler würde meckern xdNun, weder der Intel noch der GCC haben gemeckert... das liegt wohl daran, daß ich zwar in der Basisklasse ein "virtuell" vor dem Destruktor hatte, aber auch bei der abgeleiteten Basisklasse
Nachdem ich die "virtuell" Deklarationen in den abgeleiteten Destrokturen entfernt hatte, verschwand mein Memory Leak... es war wohl einfach zuviel des Guten :SIn deinem oben gegebenen Beispiel war der Basis-Dtor nicht virtuell (und ob du den abgeleiteten Dtor virtual definierst, ist dann letztendlich egal)
-
CStoll schrieb:
In deinem oben gegebenen Beispiel war der Basis-Dtor nicht virtuell (und ob du den abgeleiteten Dtor virtual definierst, ist dann letztendlich egal)
Das stimmt, war auch nur ein Code-Snap... in meinem Produktions-Code war es doppelt "virtuell", es gab auch keine Warnings... ich kann Euch auch nur wiedergeben, was mir widerfahren ist. GCC compilierte den Code ja einwandfrei, während der Intel Compiler mit dem Doppelten-Lottchen spazieren fuhr...
-
intelc und vc machen bei virtuell manchmal durchaus seltsamme dinge.
-
rapsoo schrieb:
intelc und vc machen bei virtuell manchmal durchaus seltsamme dinge.
schmarren.
-
hustbaer schrieb:
rapsoo schrieb:
intelc und vc machen bei virtuell manchmal durchaus seltsamme dinge.
schmarren.
Ja, das ist dann das Resultat.