Speicherleck nur beim "new"?
-
david.dda schrieb:
Ja, ich will wissen, wann ein Speicherleck entsteht. Ich dachte immer wenn ein Zeiger definiert wird. zB. char* zeiger; muss er nachher auch gelöscht werden.
Nein, ein Zeiger ist auch nur eine normale Variable.
char* zeigermuss genausowenig gelöscht werden wieint zahl. Überhaupt werden nicht Zeiger gelöscht, sondern Speicherblöcke freigegeben und Objekte zerstört.In dem Beispiel, den ich im vorigen Beitrag reinkopiert habe, wird der Zeiger pData auch nicht mit new erzeugt, sondern es wurde ihm irgendwelche Adresse einer Variable zugewiesen und trotzdem wurde dann im Change Log vom FileZillaServer (von der auch dieser Quellcodeabschnitt herkommt) angegeben, dass delete pData vergessen wurde, und dass es zu einem memory leak führen würde.
Ja, der Zeiger wird folgendermaßen initialisiert:
t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data;Das heißt, er wird als Kopie von pConnOp->data angelegt. Ob das ein Speicherleck ist oder nicht hängt ganz entscheidend davon ab, was in pConnOp->data drin steht und was mit dem Zeiger später passiert.
Ich wage mal die kühne Behauptung, dassdelete pData;(zumindest aus Design-Perspektive) nicht die Lösung dieses Speicherlecks ist.Jetzt wollte ich wissen, wann also ein memory leak wirklich entstehen kann? Muss ich einen Zeiger mit new definieren, diesen dann an eine Variable mit einem * Zeichen zeigen lassen zB. zeiger = *variabel; (damit die Adresse in den Zeiger kopiert wird) und erst nachher wenn ich den Zeiger nicht lösche kommt es zu einem Memory leak? Oder warum sollte ich eigentlich den Zeiger mit new definieren?
Ein Speicherleck entsteht, wenn du mit
newein Objekt erstellst und dieses Objekt nicht irgendwann mitdeletewieder löschst. Wieviele Zeiger zwischendrin auf dieses Objekt zeigen, ist völlig irrelevant. Die Zeiger werden ja auch nicht gelöscht, sondern das Objekt. Mal ein paar Beispiele:int a; int *p1 = &a; // p zeigt auf die lokale Variable a. kein new also kein delete notwendig new int; // Objekt wird angelegt, aber die Adresse keinem Zeiger zugewiesen. Wie soll man jetzt noch delete aufrufen können? geht nicht => Speicherleck int *p2 = new int; delete p2; // ok, p2 zeigt auf ein mit new angelegtes Objekt, das wird hier gelöscht int *p3 = new int; p3 = &a; // und was ist mit dem mit new angelegten Objekt? Keine Chance mehr, es freizugeben => Speicherleck int *p4 = new int; int *p5 = p4; p4 = 0; delete p5; // p5 zeigt auf das mit new angelegte Objekt (zwischendurch haben mal p4 und p5 gleichzeitig darauf gezeigt), das löschen wir hier, alles klar
-
david.dda schrieb:
Ich dachte immer wenn ein Zeiger definiert wird.
[...]
Muss ich einen Zeiger mit new definieren
[...]Die Wortwahl ist falsch und deutet auf ein falsches Verständnis von Zeigern hin. Ein Zeiger wird NICHT mit new definiert.
char* p = new char[100];Zu beachten: Ds
a steht ein Gleichheitszeichen zwischen char* p und new. p wird als char* definiert, aber mit new wird der Zeiger initialisiert.btw, memory-leaks werden nicht durch den Zeiger selbst verursacht sondern durch new (bei fehlendem delete)
Ich habe das Fegühl das Du Zeiger mit Referenzen verwechselst...
-
ok, danke sehr, ich hätte einige Bemerkungen zu dem letzten Beispiel - Stimmen diese Behauptungen?
int *p4 = new int; int *p5 = p4; p4 = 0; delete p5; // p5 zeigt auf das mit new angelegte Objekt (zwischendurch haben mal p4 und p5 gleichzeitig darauf gezeigt), das löschen wir hier, alles klarint *p4 = new int; -> p4 wurde als ein neues Objekt erstellt - muss gelöscht werden
int *p5 = p4; -> ein Zeiger auf p4 - der Zeiger p5 wurde nicht mit neu erzeugt - daher muss nicht gelöscht werden
p4 = 0; -> p4 zeigt auf andere Adresse - kann daher mit delete p4 nicht mehr gelöscht werden - daher würde ein Speicherleck entstehen
delete p5; -> damit der Speicherleck nicht entsteht, löscht man die Adresse von p4, die in p5 gespeichert wurde. (das Objekt, dass unter dieser Adresse erzeugt wurde)Ich habe noch einige Unklarheiten: warum erstellt man mit einem Zeiger direkt ein Objekt? Ich glaubte, ein Objekt wird erstellt (z.B. Person p=new Person(); ) und der Zeiger zeigt nur darauf hin (z.B. Person *z = &p; ). Was ist der Sinn des Erzeugens eines Objektes mit einem Zeiger? - (z.B. Person *neu = new Person(); ) - bedeutet diese Initialisierung, dass ein Objekt Person erzeugt wird, irgendwo im Speicher abgelegt wird und nur durch den Zeiger erreicht werden kann? - sprich - es ist gleich wie ( Person p=new Person(); mit Person *z = &p; ) mit dem Unterschied, dass beim "Person *neu = new Person();" "neu" irgendwo im Hintergrund gespeichert wurde und kann nicht mehr zugegriffen werden aber nur mit dem Zeiger z angesprochen werden?
-
Was ist der Sinn des Erzeugens eines Objektes mit einem Zeiger?
Man erstellt mit einem Zeiger kein Objekt.
new fordert Speicher für ein Objekt im freien Speicher an, der allerdings unbenannt ist. Die einzige Möglichkeit auf diesen Speicher zuzugreifen, ist über einen Zeiger.
MfG,
ScRaT
-
Sebastian Pizer schrieb:
Schau nochmal in Dein C++ Buch rein. Lies Dir die Kapitel über Zeiger und dynamische Speicherverwaltung nochmal durch.
Lern überhaupt erstmal die Grundlagen von C++. Dein mentales Modell von dem, was bei C++ so abgeht, scheint ganz schön verzerrt zu sein. Ich kann nur für mich sprechen, aber bei mir geht die Motivation sehr schnell runter, wenn ich merke, dass der Hilfesuchende von Tuten und Blasen keine Ahnung hat. Man kann Dir so schlecht helfen, wenn Du nicht mal dieselbe Sprache sprichst wie wir und es ständig Missverständnisse gibt. Der Verweis auf ein gutes Lehrbuch, was Du lesen solltest, schlägt 2 Fliegen mit einer Klappe: (1) Du entlastest uns, indem Du Dir selbst hilfst. (2) Dir wird viel besser geholfen, lernst wichtige Grundlagen, die richtige Terminologie etc. Mit trial-and-error kommst Du bei C++ nicht weit.
Gruß,
SP
-
david.dda schrieb:
Stimmen diese Behauptungen?
int *p4 = new int; // p4 wurde als ein neues Objekt erstellt - muss gelöscht werden int *p5 = p4; // ein Zeiger auf p4 - der Zeiger p5 wurde nicht mit neu erzeugt - daher muss nicht gelöscht werden p4 = 0; // p4 zeigt auf andere Adresse - kann daher mit delete p4 nicht mehr gelöscht werden - daher würde ein Speicherleck entstehen delete p5; // damit der Speicherleck nicht entsteht, löscht man die Adresse von p4, die in p5 gespeichert wurde. (das Objekt, dass unter dieser Adresse erzeugt wurde)Nein, alles falsch. Da kann jemand "Pointer" und "Pointee" nicht auseinander halten. Das scheint die Wurzel Deiner Verständnisprobleme zu sein.
int *p4 = new int; // p4 ist ein Zeiger, der auf ein dynamisch // alloziertes int-Objekt zeigt // p4 wird automatisch gelöscht! Das, worauf p4 zeigt nicht! // p4 wurde nicht mit new angelegt! Das, worauf p4 zeigt schon! int *p5 = p4; // p5 zeigt jetzt auf dasselbe Objekt wie p4 // p5 zeigt nicht auf p4 ! // p5 zeigt auf *p4 (im Moment) ! p4 = 0; // p4 zeigt auf nichts mehr delete p5; // das int-Objekt wird gelöscht, weil wir die Adresse noch // in p5 gespeichert haben.Gruß,
SP
-
david.dda schrieb:
Ich habe noch einige Unklarheiten: warum erstellt man mit einem Zeiger direkt ein Objekt?
Du meinst, warum man
int* p = new int;schreibt? Naja, du kannst auch erst den Zeiger definieren und dann zuweisen:int *p; p = new int;aber aus einer Reihe von guten Gründen bevorzugt man die Initialisierung.Ich glaubte, ein Objekt wird erstellt (z.B. Person p=new Person(); ) und der Zeiger zeigt nur darauf hin (z.B. Person *z = &p; ).
Wo hast du denn das her? Das erste funktioniert ja schonmal gar nicht. Wenn du
Person p = ...schreibst, deklarierst dupals Objekt vom TypPerson.new Person()erstellt aber ein neues Objekt vom TypPersonauf dem Freispeicher und liefert die Adresse dieses Objekts (d.h. einen Zeiger darauf zurück). Du kannst aber den Zeiger nicht an p zuweisen, p ist ja kein Zeiger.Was ist der Sinn des Erzeugens eines Objektes mit einem Zeiger? - (z.B. Person *neu = new Person(); ) - bedeutet diese Initialisierung, dass ein Objekt Person erzeugt wird, irgendwo im Speicher abgelegt wird und nur durch den Zeiger erreicht werden kann?
Genau, und noch mehr: Das erzeugte Person-Objekt bleibt solange gültig, bis es mit delete zerstört wird. Die Alternative zum Verwenden von new (die du immer wieder falsch wiedergibst, da muss ich jetzt auch mal dringend zu einem vernünftigen Lehrbuch raten) funktioniert so:
Person p; // ein Objekt vom Typ Person wird erzeugt und p genanntDiese Objekte werden zerstört, wenn der Gültigkeitsbereich von p verlassen wird, deshalb nennt sich das auch automatische Speicherdauer:
int main() { Person p; // nix new p.bla(); } // hier hört p auf zu existieren, es wird automatisch der Destruktor aufgerufen
-
david.dda schrieb:
Person p = new Person();
Nur so auf Verdacht: C++ != Java. Diese Sprachen bitte nicht durcheinander werfen. Was die Speicherverwaltung, Erzeugung von "Objekten", "Referenzen" und das Objekt-Modell angeht, unterscheiden sich diese Sprachen gewaltig.
-
Ich habe schon einige Bücher über C++ gelesen, aber weil es nur viel Theorie ohne Praxis war, versteht man vieles nicht so eindeutig. Jedenfalls werde ich mir noch das Buch besorgen. Was ich fragen wollte:
Hier im Quellcode wird ein Zeiger pData erstellt. Dieser zeigt auf einen Struct, der im zweiten Teil abgebildet ist.case USERCONTROL_CONNOP_TRANSFEROFFSETS: { t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data; buffer = pData->pData; len = pData->len; unsigned char* p = buffer + 2; int* userid; __int64* offset; while ((p - buffer + 12) <= len) { userid = (int*)p; offset = (__int64*)(p + 4); t_connectiondata& data = m_UsersList[*userid]; data.currentOffset = *offset; p += 12; } // DA SOLLTE EINGEFÜGT WERDEN: delete pData; } break; }Struct für pData
typedef struct { void *data; int op; int userid; } t_connop;pConnOp (dass pData definiert: t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data;) wird vom dem Eingabeparameter in der gleichen Methode übernohmen, wobei LPARAM ein _W64 long ist:
LRESULT CServer::OnServerMessage(CServerThread* pThread, WPARAM wParam, LPARAM lParam) { t_connop *pConnOp = reinterpret_cast<t_connop*>(lParam); ...und die Methode OnServerMessage wird so verwendet:
std::list<CServerThread::t_Notification> notifications; pThread->GetNotifications(notifications); for (std::list<CServerThread::t_Notification>::const_iterator iter = notifications.begin(); iter != notifications.end(); iter++) if (pServer->OnServerMessage(pThread, iter->wParam, iter->lParam) != 0) break;Ich kann hier also keinen Grund finden, warum pData wirklich gelöscht werden sollte, da kein Objekt erzeugt wird.
-
david.dda schrieb:
Ich habe schon einige Bücher über C++ gelesen,
welche?
david.dda schrieb:
Jedenfalls werde ich mir noch das Buch besorgen.
welches?
Sorry, aber Deine Glaubwürdigkeit ist, wegen dem, was Du so von Dir gibst, nahe Null. Ein Tipp für's nächste mal: Wenn Du demnächst irgendwo nochmal eine Frage stellst, könntest Du auch dein Erfahrungs- und Wissensstand verraten. Diese Info kann nie schaden und erleichtert es womöglich den Hilfsbereiten deine Fragen besser einzuordnen.
david.dda schrieb:
Was ich fragen wollte:
[...code_fragment...]
Ich kann hier also keinen Grund finden, warum pData wirklich gelöscht werden sollte, da kein Objekt erzeugt wird.Das kann man gar nicht anhand dieses kleinen Code-Fragments beurteilen. Man müsste schon die Zusammenhänge kennen. Wo ist das dazugehörige new? Was hat sich der Programmierer dabei gedacht? Ist es irgendwo dokumentiert, wie die Speicherverwaltung der Puffer in diesem Kontext gedacht ist? u.s.w.
Gruß,
SP
-
Du mußt noch weiter im Code suchen, nämlich da, wo die Elemente der Liste 'std::listCServerThread::t_Notification' erzeugt werden... und dort wird es wohl eine Speicherallokation für 'lParam->data' geben.
(ist aber alles andere als schöner Code, da wären shared_pointer sicherlich besser - außerdem ist das m.E. die falsche Stelle: warum wird das nicht im Destruktor von CServerThread::t_Notification gemacht???)
-
danke für den Hinweis, der "iterator" hat die Liste "notifications" durchgelaufen:
std::list<CServerThread::t_Notification> notifications; pThread->GetNotifications(notifications); //da muss die Speicherallokation für 'lParam->data' sein for (std::list<CServerThread::t_Notification>::const_iterator iter = notifications.begin(); iter != notifications.end(); iter++) if (pServer->OnServerMessage(pThread, iter->wParam, iter->lParam) != 0) break;Die Liste wurde mit "GetNotifications(notifications)" erstmals gefüllt (dabei wurde der Inhalt dieser Liste mit der Liste "m_pendingNotifications" umgetauscht:
void CServerThread::GetNotifications(std::list<CServerThread::t_Notification>& list) { EnterCritSection(m_threadsync); m_pendingNotifications.swap(list); if (m_throttled) SetPriority(THREAD_PRIORITY_NORMAL); LeaveCritSection(m_threadsync); }und die Liste "m_pendingNotifications" wurde wiederum so gefüllt:
void CServerThread::SendNotification(WPARAM wParam, LPARAM lParam) { EnterCritSection(m_threadsync); t_Notification notification; notification.wParam = wParam; notification.lParam = lParam; if (m_pendingNotifications.empty()) PostMessage(hMainWnd, m_nNotificationMessageId, 0, 0); m_pendingNotifications.push_back(notification); // Check if main thread can't handle number of notifications fast enough, throttle thread if neccessary if (m_pendingNotifications.size() > 200 && m_throttled < 3) { SetPriority(THREAD_PRIORITY_IDLE); m_throttled = 3; } else if (m_pendingNotifications.size() > 150 && m_throttled < 2) { SetPriority(THREAD_PRIORITY_LOWEST); m_throttled = 2; } else if (m_pendingNotifications.size() > 100 && !m_throttled) { SetPriority(THREAD_PRIORITY_BELOW_NORMAL); m_throttled = 1; } LeaveCritSection(m_threadsync); }Diese Methode "SendNotification" wurde dann mehrmals benutzt, hier ist ein Beispiel:
t_connop *op = new t_connop; op->data = 0; op->op = USERCONTROL_CONNOP_REMOVE; op->userid = m_userid; m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op);Es wurde also ein Zeiger "op" erstellt, der einen struct mit new erzeugt:
typedef struct { void *data; int op; int userid; } t_connop;Deswegen musste dann dieses neues struct-Objekt, an dem "op" Zeiger hinweist, gelöscht werden. Ich hoffe, es stimmt so.
Antwort zu der vorigen Frage:
Ich habe C++Tutorial.pdf (ca. 140 Seiten) und Teach Yourself C++ in 21 days (da habe ich einige Teile übersprungen) und dann noch ziemlich viel Online, gelesen (zuletzt tutorial vom schornboeck nochmals über die Zeiger und dynamische Speicherreservierung). Ich habe mich ca. 2 Jahre privat mit Java beschäftigt und schon auch einiges programmiert (z.B. einen Tetris Spiel) und seit einem halben Jahr mit C++, aber eher viel theoretisch und nur mal sehr kleine Applikation ausprobiert - wie einen Taschenrechner mit Hilfe von Visual Studio. Deswegen scheinen Dir meine Fragen vielleicht so primitiv. In einem halben Jahr bin ich sicher wieder bißchen weiter.
-
david.dda schrieb:
Antwort zu der vorigen Frage:
Ich habe C++Tutorial.pdf (ca. 140 Seiten) und Teach Yourself C++ in 21 days (da habe ich einige Teile übersprungen) und dann noch ziemlich viel Online, gelesen (zuletzt tutorial vom schornboeck nochmals über die Zeiger und dynamische Speicherreservierung). Ich habe mich ca. 2 Jahre privat mit Java beschäftigt und schon auch einiges programmiert (z.B. einen Tetris Spiel) und seit einem halben Jahr mit C++, aber eher viel theoretisch und nur mal sehr kleine Applikation ausprobiert - wie einen Taschenrechner mit Hilfe von Visual Studio.Da ich nicht besonders viel von C++-Onlinetutorials halte, würde ich dir auch zu einem gescheiten Buch wie z. B. dem C++-Primer raten. Weil du ja auch folgendes geschrieben hattest:
david.dda schrieb:
Ich habe schon einige Bücher über C++ gelesen, aber weil es nur viel Theorie ohne Praxis war, versteht man vieles nicht so eindeutig.
würde ich dir das Buch auch deswegen empfehlen, weil du dort Unmengen an Übungsaufgaben findest an denen du dich versuchen kannst.

PS: Wer weiß, wenn du deine Eltern/Verwandten/Bekannten darauf ansprichst, dann kriegst du es vielleicht als Weihnachtsgeschenk. :xmas1:
-
Hallo david.dda,
die Freigabe des Speichers bezieht sich aber auf eine evtl. Zuweisung von "op->data = static_cast<void *>(new X);". Gibt es auch solche (oder ähnliche) Speicherallokationen?
Aber wie schon geschrieben, ist das keine gute Implementierung, anscheinend nur ein Notbehelf, um Speicherlecks zu fixen...
Edit: und auch sehr fehleranfällig, falls z.B. konstante Zuweisungen á laop->data = (void *)42; // oder op->data = (void *)"hello";passieren (habe extra mal kein static_cast benutzt, um zu zeigen, was alles so programmiert werden könnte...)
-
danke, es stimmt, es wurde eine Allokation erstellt, die dann mit dem vergessenen delete statement nachträglich korrigiert wurde (es wurde also der reservierte Speicher an dem op->data zeigt, gelöscht - in diesem Fall der Speicher an dem "conndata" zeigt - ):
t_connectiondata_changeuser *conndata = new t_connectiondata_changeuser; t_connop *op = new t_connop; op->data = conndata; op->op = USERCONTROL_CONNOP_CHANGEUSER; op->userid = m_userid; conndata->user = m_status.user; m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op); return TRUE; }*conndata ist ein Struct:
struct t_connectiondata_changeuser { CStdString user; };nun kann ich aber nicht rausfinden, wo auch der Speicher an dem *op zeigt gelöscht wurde. Es sieht so aus, als würde dieser nicht deallokiert.
Mein Source code analyzer meldet folgendes:
*Memory Leak
(Code Quality, Control flow)The function SendTransferinfoNotification() in ControlSocket.cpp allocates memory on line 2847 and fails to free it.*
Line 2847 enthält folgendes Code: t_connop *op = new t_connop;
-
david.dda schrieb:
nun kann ich aber nicht rausfinden, wo auch der Speicher an dem *op zeigt gelöscht wurde. Es sieht so aus, als würde dieser nicht deallokiert.
Auch, wenn Du das als Frage formuliert hättest, kann man Dir hier nicht helfen, weil wir "Dein Analyse-Tool" nicht kennen und keinen Überblick über das Programm haben, was Du analysierst. Du anscheinend auch nicht.
david.dda schrieb:
Mein Source code analyzer
Ja welcher ist dass denn nun?!
david.dda schrieb:
meldet folgendes:
*Memory Leak
(Code Quality, Control flow)The function SendTransferinfoNotification() in ControlSocket.cpp allocates memory on line 2847 and fails to free it.*
Line 2847 enthält folgendes Code: t_connop *op = new t_connop;
Tja, und nun? Was soll uns das sagen? Schau mal in der Dokumentation zu dem von Dir nicht näher spezifizierten Tool nach, wie so eine Meldung zu bewerten ist. Der Satz "The function..." ist sicherlich richtig. Aber das allein garantiert Dir noch kein Memory-Leak. Es könnte also ein flascher Alarm sein. Es könnte aber auch richtig sein, weil das Tool nirgends wo ein "
delete p" gefunden hat, wobei p ein Ausdruck vom Typt_connop*ist. Dann würde ich auch ein Speicherleck melden, allerdings nicht mit so einem blöden "The function..."-Text. Das ist nämlich so nichtssagend. Natürlich muss man nicht immer in derselben Funktion den Speicher freigeben, den man angefordert hat. Im Gegenteil. Der Freispeicher ist gerade dazu da, Objekte anzulegen, die eine längere Lebensdauer haben und nach verlassen einer Funktion nicht sofort wieder zerstört werden, so wie es bei automatischen Objekten der Fall wäre.Gruß,
SP
-
ich habe den Code von FileZillaServer mit 5 Source Code Analysatoren durchgelaufen. CppCheck und RATS - beide sind nicht kommerzielle Werkzeuge und finden nur offensichtliche Fehler, wie Gebrauch von gefährlichen C++ Funktionen (strcpy..) dann habe ich C++Test verwendet - dieses Tool läßt sich super konfigurieren und ist sehr übersichtlich, PC-Lint - da habe ich noch Schwierigkeiten bei der Konfig. und Fortify - von dem auch die Fehlermeldung stamm, Fortify ist einfach zu installieren, leicht in der Benutzung und hat viele Features (Summary, Recommendations, Diagram, Details...) für die Fehlermeldungen. Allerdigs konnte keines von diesen Tools den Memory leak über den wir die ganze Zeit sprechen finden.
-
david.dda schrieb:
Allerdigs konnte keines von diesen Tools den Memory leak [...] finden.
Warum wundert Dich das?
-
also hälst Du nicht viel von diesen Tools?
Es sind statische Source Code Analysatoren, dynamische würden den leak vielleicht finden, aber die habe ich nicht ausprobiert. Ich weiß auch nicht wie die einzelnen Tools den Quellcode analysieren. In der Dokumentation zu diesen gibt es zwar einige Beispiele, diese sind aber eher ziemlich kurz und einfach, damit man so ungefähr weiß, wie ein memory leak.. im Quellcode gefunden wird:Consider the example: char *p, *q = 0; p = malloc(10); p = q; // Warning -- memory leak We are able to issue a Warning because the return from malloc has an allocation flag that indicated that the returned value points to a freshly allocated region that is not going to be freed by itself.
-
david.dda schrieb:
Ich habe schon einige Bücher über C++ gelesen, aber weil es nur viel Theorie ohne Praxis war, versteht man vieles nicht so eindeutig.
Eigendlich ist es doch genau umgekehrt: Man kann die Praxis nur verstehen wenn man vorher die Theorie begriffen hat. Ansonsten läuft man Gefahr die Praxis nicht zu verstehen, sondern zu interpretieren, wodurch beliebig falsche Denkmodelle entstehen können, wie wir an diesem Beispiel zum Verhalten von Zeigern ja sehr schön beobachten konnten...
Technisch gesehen ist die Regel für Speicherverwaltung einfach: Jedes new muß durch ein passendes delete wieder freigegeben werden. Das wars auch schon. Memory-leaks entstehen immer dann, wenn diese Regel gebrochen wird.
david.dda schrieb:
ich habe den Code von FileZillaServer mit 5 Source Code Analysatoren durchgelaufen.
Code Analysator != Memory-leak detector. Du benutzt also die falschen Tools und kannst daher auch nix finden.
Das ist ungefähr so als würdest Du einen Schraubenzieher benutzen um einen Baum zu fällen... Und Dich dann wundern warum das nicht so richtig funktioniert...