![]() |
Speicherlecks in fremdem Code/Programm finden
Hallo Leute :),
ich hoffe, die Experten für C++ sind anwesend, denn ich habe dazu eine Problemstellung. Gegeben ist eine Software, die jemand anders in Visual C++ 2008 geschrieben hat, und eindeutig Speicherlecks aufweist. Es handelt sich hierbei um ein nicht-visuelles Client/Server- oder besser Server/Agent-System, bei dem der Agent als Dienst auf einem Windows läuft. Um den Agent geht es und nur der ist auch relevant. Wie komme ich auf die Speicherlecks? Mit der Laufzeit des Diensts wird der Speicherverbrauch immer größer, vor allem stechen hier die Private Bytes und das Private Working Set heraus (ermittelt mit Process Explorer und Process Hacker). Um mal eine Größenordnung zu nennen: Nach dem Start des Diensts bewegt sich dessen Speicherverbrauch so um die 5 MB, nach einer Woche sind es bereits 20-25 MB; im x64-Kompilat ist es noch schlimmer, da habe ich nach einer Woche Laufzeit schon über 100 MB gesehen. Würde man den Agent/Dienst nicht wöchentlich neu starten, stiege der Speicherverbrauch immer weiter an. Vor vielen Jahren, als der wöchentliche Neustart noch nicht per Skript durchgeführt wurde, war das auch so. Ich kann mich leider nicht mehr an einen Maximalwert erinnern, vermutlich waren es mehrere Hundert MB; was dann letztlich der Anlass zum Neustart des Dients per Skript war. Leider gibt's einige Faktoren, die die Untersuchung für mich deutlich erschweren:
Wie kann ich die Sache angehen? Hilft es, wenn ich sage, um welche Software es geht? Einerseits wäre ich dankbar, wenn mir jemand zur Hand gehen könnte bei der Sache, andererseits möchte ich nicht, dass jemand anders meine Arbeit macht (auch wenn die freiwillig ist). Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Um hier konkret mit Ideen aushelfen zu können, sind die Angaben zum Service etwas zu knapp.
Was macht er? (Grobe Beschreibung der Aufgabe.) Hatte vor Jahren mal mit 'nem in Delphi geschriebenen Service so ein Speicherproblem. Grob: Der Service sollte aus der Serverlandschaft alle 15 Minuten Statusinformationen sammeln und daraus Webseiten generieren, die per Webserver abrufbar waren. Für das Sammeln der Statusinformationen wurde unter Anderem per WMI auf die Server zugegriffen. Und darin war irgendwo ein Speicherloch, das wir nicht wegbekommen haben. Haben dann aus dem Service ein Konsolenprogramm gemacht, das per Taskplaner alle 15 Minuten gestartet wurde. Damit war das Speicherproblem zwar nicht behoben, aber fiel nicht mehr auf, da es nur noch für die Laufzeit des Konsolenprogrammes bestand. |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Wenn diese Standardfunktionen irgendwie Speicher reservieren, sind sie sicher nicht selbst die Ursache, aber deren Aufruf im Kontext ggf. schon. Beispiel:
Delphi-Quellcode:
Nun steht im Stacktrace des Leaks ggf. auch TObject.Create drin und evtl. auch GetMem usw.
procedure FillMyMem;
var Example: TExample; begin Example := TExample.Create; end; Und obwohl beides nicht die Verursacher sind, zeigt der Stacktrace wo der Speicher verbraten wird, da auch FillMyMem und TExample.Create auftauchen. |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Zitat:
Code:
Aus dem Call Stack wird auch klar, dass es um Munin geht, konkret
Visual Leak Detector Version 2.3 installed.
Outputting the report to the debugger and to c:\VC\munin-node\memory_leak_report.txt WARNING: Visual Leak Detector detected memory leaks! ---------- Block 116 at 0x003D5C00: 64 bytes ---------- Call Stack: c:\programme\microsoft visual studio 9.0\vc\include\xmemory (43): munin-node.exe!std::_Allocate<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > + 0xC bytes c:\programme\microsoft visual studio 9.0\vc\include\xmemory (145): munin-node.exe!std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::allocate + 0xB bytes c:\programme\microsoft visual studio 9.0\vc\include\vector (1178): munin-node.exe!std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >::_Insert_n + 0xF bytes c:\programme\microsoft visual studio 9.0\vc\include\vector (719): munin-node.exe!std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >::resize + 0x5C bytes c:\vc\munin-node\src\extra\inifile.cpp (227): munin-node.exe!CIniFile::SetValue c:\vc\munin-node\src\extra\inifile.cpp (87): munin-node.exe!CIniFile::ReadFile c:\vc\munin-node\src\core\munin-node.cpp (65): munin-node.exe!main f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (582): munin-node.exe!__tmainCRTStartup + 0x19 bytes f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (399): munin-node.exe!mainCRTStartup 0x7C817067 (File and line number not available): kernel32.dll!RegisterWaitForInputIdle + 0x49 bytes Data: 00 00 00 00 CD CD CD CD 42 72 6F 61 64 63 61 73 ........ Broadcas 74 49 50 00 CD CD CD CD 0B 00 00 00 0F 00 00 00 tIP..... ........ 00 00 00 00 CD CD CD CD 55 49 44 00 CD CD CD CD ........ UID..... CD CD CD CD CD CD CD CD 03 00 00 00 0F 00 00 00 ........ ........ ---------- Block 127 at 0x003D5C80: 4 bytes ---------- Call Stack: c:\vc\munin-node\src\core\muninpluginmanager.cpp (61): munin-node.exe!MuninPluginManager::MuninPluginManager + 0x7 bytes 0x004665C5 (File and line number not available): munin-node.exe!MuninNodeServer::MuninNodeServer + 0x65 bytes c:\vc\munin-node\src\core\service.cpp (135): munin-node.exe!CService::Run + 0x2E bytes c:\vc\munin-node\src\core\service.cpp (63): munin-node.exe!CService::Start c:\vc\munin-node\src\core\munin-node.cpp (110): munin-node.exe!main f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (582): munin-node.exe!__tmainCRTStartup + 0x19 bytes f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (399): munin-node.exe!mainCRTStartup 0x7C817067 (File and line number not available): kernel32.dll!RegisterWaitForInputIdle + 0x49 bytes Data: E0 7F 47 00 ..G..... ........ ---------- Block 1 at 0x003D5FD8: 24 bytes ---------- Call Stack: c:\programme\microsoft visual studio 9.0\vc\include\xmemory (43): munin-node.exe!std::_Allocate<std::_Tree_nod<std::_Tmap_traits<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> >,0> >::_Node> + 0xC bytes c:\programme\microsoft visual studio 9.0\vc\include\xmemory (145): munin-node.exe!std::allocator<std::_Tree_nod<std::_Tmap_traits<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> >,0> >::_Node>::allocate + 0xB bytes c:\programme\microsoft visual studio 9.0\vc\include\xtree (1384): munin-node.exe!std::_Tree<std::_Tmap_traits<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> >,0> >::_Buynode + 0xD bytes c:\programme\microsoft visual studio 9.0\vc\include\xtree (1178): munin-node.exe!std::_Tree<std::_Tmap_traits<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> >,0> >::_Init + 0x8 bytes c:\programme\microsoft visual studio 9.0\vc\include\xtree (511): munin-node.exe!std::_Tree<std::_Tmap_traits<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> >,0> >::_Tree<std::_Tmap_traits<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,vo c:\programme\microsoft visual studio 9.0\vc\include\map (104): munin-node.exe!std::map<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> > >::map<unsigned long,void *,std::less<unsigned long>,std::allocator<std::pair<unsigned long const ,void *> > > c:\vc\munin-node\src\plugins\disk\smartreader.cpp (14): munin-node.exe!CSmartReader::CSmartReader + 0x59 bytes c:\vc\munin-node\src\plugins\disk\smartreader.cpp (393): munin-node.exe!CSmartReader2::CSmartReader2 + 0x2B bytes c:\vc\munin-node\src\plugins\disk\smartreader.cpp (413): munin-node.exe!`dynamic initializer for 'g_SmartReader'' + 0x28 bytes 0x1023C02C (File and line number not available): MSVCR90D.dll!initterm + 0x1C bytes f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (497): munin-node.exe!__tmainCRTStartup + 0xF bytes f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (399): munin-node.exe!mainCRTStartup 0x7C817067 (File and line number not available): kernel32.dll!RegisterWaitForInputIdle + 0x49 bytes Data: D8 5F 3D 00 D8 5F 3D 00 D8 5F 3D 00 CD CD CD CD ._=.._=. ._=..... CD CD CD CD 01 01 CD CD ........ ........ ---------- Block 2 at 0x003D6030: 548 bytes ---------- Call Stack: c:\programme\microsoft visual studio 9.0\vc\include\xmemory (43): munin-node.exe!std::_Allocate<std::_Tree_nod<std::_Tmap_traits<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAILS> >,0> >::_Node> + 0xF bytes c:\programme\microsoft visual studio 9.0\vc\include\xmemory (145): munin-node.exe!std::allocator<std::_Tree_nod<std::_Tmap_traits<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAILS> >,0> >::_Node>::allocate + 0xB bytes c:\programme\microsoft visual studio 9.0\vc\include\xtree (1384): munin-node.exe!std::_Tree<std::_Tmap_traits<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAILS> >,0> >::_Buynode + 0xD bytes c:\programme\microsoft visual studio 9.0\vc\include\xtree (1178): munin-node.exe!std::_Tree<std::_Tmap_traits<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAILS> >,0> >::_Init + 0x8 bytes c:\programme\microsoft visual studio 9.0\vc\include\xtree (511): munin-node.exe!std::_Tree<std::_Tmap_traits<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAILS> >,0> >::_Tree<std::_Tmap_traits<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std c:\programme\microsoft visual studio 9.0\vc\include\map (104): munin-node.exe!std::map<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAILS> > >::map<unsigned char,ST_SMART_DETAILS,std::less<unsigned char>,std::allocator<std::pair<unsigned char const ,ST_SMART_DETAIL c:\vc\munin-node\src\plugins\disk\smartreader.cpp (14): munin-node.exe!CSmartReader::CSmartReader + 0x6E bytes c:\vc\munin-node\src\plugins\disk\smartreader.cpp (393): munin-node.exe!CSmartReader2::CSmartReader2 + 0x2B bytes c:\vc\munin-node\src\plugins\disk\smartreader.cpp (413): munin-node.exe!`dynamic initializer for 'g_SmartReader'' + 0x28 bytes 0x1023C02C (File and line number not available): MSVCR90D.dll!initterm + 0x1C bytes f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (497): munin-node.exe!__tmainCRTStartup + 0xF bytes f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (399): munin-node.exe!mainCRTStartup 0x7C817067 (File and line number not available): kernel32.dll!RegisterWaitForInputIdle + 0x49 bytes Data: 30 60 3D 00 30 60 3D 00 30 60 3D 00 CD CD CD CD 0`=.0`=. 0`=..... CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........ ![]() ![]() Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Eine Warnung für diejenigen, die sich den Dienst installieren möchten: Auf gar keinen Fall munin-node.exe mit dem Parameter -uninstall aufrufen, sonst wird die komplette Ereignisanzeige (Bereich Anwendungen) zerstört! Das ist der gravierendste Bug, den ich behoben habe; in der aktuellen Beta (1.6.1.0) von Github scheint er ebenfalls behoben zu sein.
Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Bei neueren VS Versionen könnte evtl. das hier helfen:
![]() Visual Studio 2015 Community Edition gibt es als kostenlosen Download und die Express Variante kann man auch als Testversion beziehen. - Der Leak in
Delphi-Quellcode:
ist glaube ich schonmal ein False-Positive. Die Container sind alle Stack-allocated; sprich: sie werden automatisch freigegeben, sobald die Klasseninstanz aus dem Scope läuft. Generell ist es in C++ eigentlich sehr schwierig Speicher zu leaken. Ausschau halten solltest du nach allen Stellen, die entweder Objekte mit
CIniFile
Delphi-Quellcode:
auf dem Heap erstellen oder manuellen
new
Delphi-Quellcode:
,
malloc
Delphi-Quellcode:
, etc. Aufrufen.
VirtualAlloc
|
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Zitat:
Zitat:
--- Der gesamte Report von VLD ist übrigens noch deutlich länger (über 100 KB) und enthält am Ende diese Zeilen:
Code:
Ich kann den bei Interesse gern zur Verfügung stellen.
Visual Leak Detector detected 43 memory leaks (9432 bytes).
Largest number used: 11008 bytes. Total allocations: 46696 bytes. Visual Leak Detector is now exiting. Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Anderes Beispiel: Delphi: dlg := new TMyDialog(..) --> dlg.Free(); C++: MyDialog dlg(..); Stack-alloziierte Objekte gibt es in Delphi nicht, deshalb muss man sie auch wegräumen. |
AW: Speicherlecks in fremdem Code/Programm finden
Hab' mir mal die INI zum Programm angeschaut. In diesem Abschnitt
Code:
kann man doch konfigurieren, welche Plugins genutzt werden sollen.
[Plugins]
; Plugin Section, 1 enables plugin, 0 disables Disk=1 Memory=1 Processes=1 Network=1 MbmTemp=1 MbmVoltage=1 MbmFan=1 MbmMhz=1 SMART=0 HD=1 Cpu=1 SpeedFan=1 External=1 Wenn möglich, einen eigenen Server zum Testen nehmen und erstmal alle Plugins deaktivieren. Speicherentwicklung über ein paar Stunden beobachten. Wenn da nix passiert, der Reihe nach jeweils ein Plugin aktivieren und wieder beobachten. Leider wird das sehr zeitaufwändig, wenn man 'ne Woche beobachten muss, um Speicherfresser zu entdecken. Eventuell kannst Du aber auch in einem kürzeren Zeitraum schon eine Tendenz erkennen. Gehe mal davon aus, dass der Speicherverbrauch kontinuierlich ansteigt und nicht ab und an sprunghaft. Da der Service auch auf die Windows-API zugreift, muss das Speicherloch nicht zwingend in dem Dienst sein, sondern kann auch irgendwo in der API liegen. Oder die Speicherlecks könnten eventuell auch durch fehlerhafte Nutzung der API hervorgerufen werden. Will meinen: Es muss nicht zwingend an eigener Speicherreservierung und fehlender Speicherfreigabe liegen. |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Ich werd erstmal den Node mit nur je einem Plugin gleichzeitg laufen lassen und über einige Stunden beobachten. Das dauert zwar länger, kann aber nebenbei laufen. Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Denke, dass es das Sinnvollste ist, erstmal pro Plugin zu testen. Wenn dann erkennbar ist, dass nur eines (und hoffentlich nicht mehrere) ein Problem verursacht.
Dann kann man anfangen die Quellen durchzusehen, um genauer zu erfahren, wo da was klemmen könnte. Probleme mit Speicherlöschern und dem Zugriff über WMI hatte ich eigentlich bei allen Windowsversionen. Generell würd' ich eine "kontinuierliche" oder aber auch "versionsübergreifende" Fehlermöglichkeit nicht zwingend ausschließen. Deine Bemerkung, dass der Fehler unter W2K nicht auftritt, ist (finde ich) wesentlich. W2K ist wohl die älteste Windowsversion, die Du in Betrieb hast. Daraus schließ ich jetzt erstmal ganz naiv, dass bei der ersten Version von Windows, die nach W2K heraus kam, irgendeine Änderung gemacht wurde, die in den Quellen nicht "nachgezogen" wurde. Oder der Fehler tritt bei der Nutzung einer Funktion auf, die es unter W2K noch nicht gab. |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Deshalb hatte ich vor vielen Jahren eine kleine Änderung eingebaut, die in den Kommentaren auf der alten Homepages des Autors zu finden war, um den Fehler zu beseitigen. Die Änderung bewirkt, dass die Fehlerprüfung in zwei Funktionen (PerfCounterMuninNodePlugin::OpenCounter() und PerfCounterMuninNodePlugin::GetConfig()) anders erfolgt. Wie gesagt ist das nur eine kleine Änderung an einem der Plugins, der restliche Code inkl. aller anderen Plugins blieb davon unberührt. Zitat:
Warten wir mal ab, was die Untersuchung der einzelnen Plugins bringt. Ärgert mich, dass ich diese Idee nicht früher hatte; aber vielleicht hatte ich sie schon, weiß aber das Testergebnis nicht mehr, schließlich schlage ich mich mit dem Problem schon seit Jahren rum... Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
![]() Normale Objekte verhalten sich so ähnlich wie Delphi-Objekte auch. Rolf |
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Delphi-Quellcode:
sollte nach Möglichkeit immer vermieden werden, wenn man C++ Code schreibt (gibt natürlich Ausnahmen).
new
|
AW: Speicherlecks in fremdem Code/Programm finden
Es gibt Neuigkeiten, und zwar gute! Ich habe das Leck schneller als gedacht eingrenzen können: es liegt eindeutig am SpeedFan-Plugin. Ist das Plugin deaktiviert, schwankt der Speicherverbrauch des Munin Node über einige Stunden maximal 12 KB (was ich als normal betrachte). Ist es aktiviert, steigt der Speicherverbrauch zwischen 100 und 800 KB pro 30 Minuten!
Hier mal eine Übersicht der mitgeschriebenen Werte. WS = Working Set, Werte in Kilobyte (KB).
Die Speicherzunahme ist auch auf Win2k zu beobachten. Warum ich hier von einem Unterschied zwischen Win2k und XP+ ausging, ist ganz einfach zu erklären: SpeedFan kam bei mir nie auf Win2k zum Einsatz, sondern erst ab XP; die Systeme mit Win2k benutzten ältere Hardware, die noch mit Motherboard Monitor auslesbar war (daher gab's keinen Grund für SpeedFan). Weitere wichtige Beobachtung: Der Speicherzuwachs ist sogar abhängig davon, wieviele weitere Rechner mit SpeedFan im LAN aktiv sind, d.h. je mehr Systeme desto stärker wächst die Größe des Munin Node! Nun muss nur noch das Leck selbst gefunden werden. Falls jemand Zeit und Lust hat, kann gern einen Blick auf den ![]() Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Meine C++-Kenntnisse tendieren gegen 0.
In der von Dir genannten Routine wird in 'ner Schleife mehr oder weniger häufig
Code:
bzw.
currentBlock = new xAPBlockHeader(currentPos);
Code:
aufgerufen. Hier wird ja wohl irgendwas neu erstellt. Was ich nicht finden kann ist die Stelle, an der wieder aufgeräumt wird.
currentBlock = new xAPBlockData(currentPos);
|
AW: Speicherlecks in fremdem Code/Programm finden
Aufgräumt wird später in Zeile 271, aber so wie ich das sehe wird im Block von 239 - 249 unter bestimmten Konditionen das
Delphi-Quellcode:
vergessen.
push_back
|
AW: Speicherlecks in fremdem Code/Programm finden
Zitat:
Zitat:
--- Ich glaube aber, das Leck gefunden zu haben - ich hoffe, ich bin da nicht vorschnell (Test läuft gerade). Im xAP-Protokoll, das SpeedFan da benutzt, wird Broadcasting eingesetzt, d.h. die Pakete aller Rechner kommen auf jedem Munin-Node an. Zusätzlich gibt es wohl Heartbeat-Pakete (Beispiel in ![]() Der Inhalt der Variable blocks wird durch die while-Schleife zusammengebaut, egal, was da für ein Paket reinkommt. Für jeden Abschnitt des Pakets wird mit new ein currentBlock erzeugt, und einzeln an blocks angehängt. In Zeile 267 wird der Inhalt der Variable blocks nur dann an die Klassenvariable m_Blocks weitergegeben, wenn die UID übereinstimmt (und es ein Datenpaket war und kein Heartbeat). Aber was passiert mit dem Inhalt der Variable blocks, wenn das nicht zutrifft, es also das Paket mit einer anderen UID oder ein Heartbeat war? Der dengelt weiter im Speicher rum, ohne zerstört zu werden, denn die Zerstörung passiert nur mit dem Inhalt der Klassenvariable beim nächsten Paket. Das erklärt auch, warum die Zunahme des Speichers mit der Anzahl der mit SpeedFan (mit aktiviertem xAP) laufenden Rechner im LAN ansteigt - mehr Heartbeats, mehr auf dem Heap erzeugte Objekte, die nicht wieder weggeräumt werden. Meine Lösung sieht daher momentan so aus, dass ich in Zeile 276 folgenden Teil zur if-Bedingung aus 267 ergänzt habe:
Code:
um alle Objekte in blocks wieder aufzuräumen. Das sollte alle nötigen Fälle abdecken.
} else {
for (std::vector<xAPBlock *>::iterator it = blocks.begin(); it != blocks.end(); it++) delete *it; } Ob's das wirklich ist (und das einzige Leck), wird sich zeigen. Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Trägt zwar nichts zur Problemlösung bei, soll aber verdeutlichen, daß es den Menschen wie den Leuten geht: Wen zur Abwechslung mal interessiert, wie ein sehr schwierig aufzuspürender Softwarefehler wochenlang gesucht, irgendwann gefunden und dann recht einfach beseitigt wurde, der möge
![]() |
AW: Speicherlecks in fremdem Code/Programm finden
Kleiner Nachtrag: Das Speicherleck ist definitiv gestopft. Nach 7,5 Stunden Laufzeit und einer Zunahme des Working Set von nur ca. 40 KB kann ich das guten Gewissens behaupten; diesmal lief es auf einem Win7 x64 mit x64 Prozess, daher ist der Wert nur bedingt vergleichbar mit den vorherigen. Möglicherweise sind noch weitere kleinere Lecks enthalten, aber das kann nur mit einem wesentlich längeren Untersuchungszeitraum ermittelt werden.
Ich habe den Code noch etwas angepasst:
Code:
So wird in jedem Fall aufgeräumt, wenn's nix zu verarbeiten gab. Wahrscheinlich könnte man die boolsche Variable sogar weglassen, weil die Funktion im "guten" Fall sowieso vorher mit return verlassen wird.
size_t SpeedFanNodePlugin::ListenerThread::ProcessBuffer(char *buffer)
{ ... bool clearblocks = false; ... if (headerBlock != NULL) { ... if (headerBlock->uid == uid && headerBlock->xAPClass == "PC.status") { ... } else { clearblocks = true; } } else { clearblocks = true; } if (clearblocks) for (std::vector<xAPBlock *>::iterator it = blocks.begin(); it != blocks.end(); it++) delete *it; ... } Danke an alle Beteiligten! :dp: Grüße Dalai |
AW: Speicherlecks in fremdem Code/Programm finden
Nach gut zwei Wochen ununterbrochener Laufzeit des Munin Node auf meinem Server (XP) und einer einzigen Zunahme des Working Set um ~75 KiB nach einem Tag (aber keiner weiteren) kann ich behaupten, dass das Leck wohl das einzige war. Beschränkt wird diese Behauptung lediglich durch das OS sowie die von mir verwendete Konfiguration, in der nahezu alle Plugins eingeschaltet sind. Ich nehme aber schon an, dass sich der Node auf anderen Windows-Versionen analog verhält.
Klasse, endlich Munin Node auf Windows-Systemen ohne geplanten Task, der selbigen jede Woche neu startet :). Danke und Grüße Dalai |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:51 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz