AGB  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein C++ Speicherlecks in fremdem Code/Programm finden

Speicherlecks in fremdem Code/Programm finden

Ein Thema von Dalai · begonnen am 30. Dez 2016 · letzter Beitrag vom 31. Jan 2017
Antwort Antwort
Seite 2 von 3     12 3   
nahpets

Registriert seit: 11. Okt 2006
2.408 Beiträge
 
Delphi 7 Professional
 
#11

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 1. Jan 2017, 16:17
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.
Stephan
Weil die Lichtgeschwindigkeit höher als die Schallgeschwindigkeit ist, hält man viele Leute für helle Köpfe, bis man sie reden hört.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.054 Beiträge
 
Delphi 5 Professional
 
#12

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 1. Jan 2017, 17:21
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.
Mmh, vielleicht hätte ich das weiter ausführen sollen. Die unterschiedlichen Codepfade für verschiedene Windows-Versionen gibt es in der offiziellen Version nicht (weder in 1.5 noch 1.6). Dafür funktionieren aber bestimmte Dinge unter Win2k gar nicht; soweit ich das momentan nachvollziehen kann, hatte das irgendwas mit dem Performance Counter Plugin zu tun.

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:
Oder der Fehler tritt bei der Nutzung einer Funktion auf, die es unter W2K noch nicht gab.
Ja, in die Richtung ging meine Vermutung auch, aber ich bin nicht in der Lage, die Unterschiede zu analysieren, um den Fehler zu finden. Das Performance Counter Plugin hatte ich schon einmal ausgeschaltet, aber Lecks gab's trotzdem.


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
  Mit Zitat antworten Zitat
Rollo62
Online

Registriert seit: 15. Mär 2007
729 Beiträge
 
Delphi 10.1 Berlin Professional
 
#13

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 2. Jan 2017, 07:14
Generell ist es in C++ eigentlich sehr schwierig Speicher zu leaken.
Womöglich meinst du wenn man konsequent alle Objekte per SmartPointer/AutoPointer/UniquePointer anlegt ?
Normale Objekte verhalten sich so ähnlich wie Delphi-Objekte auch.

Rolf
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
3.944 Beiträge
 
Delphi 10.1 Berlin Starter
 
#14

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 2. Jan 2017, 15:20
Generell ist es in C++ eigentlich sehr schwierig Speicher zu leaken.
Womöglich meinst du wenn man konsequent alle Objekte per SmartPointer/AutoPointer/UniquePointer anlegt ?
Normale Objekte verhalten sich so ähnlich wie Delphi-Objekte auch.
Das war eigentlich mehr auf die Tatsache bezogen, dass die Objekte standardmäßig Stack-allocated sind und automatisch freigegeben werden, sobald sie aus dem Scope laufen. Heap-Allocation per new sollte nach Möglichkeit immer vermieden werden, wenn man C++ Code schreibt (gibt natürlich Ausnahmen).
"Do not argue with an idiot. He will drag you down to his level and beat you with experience."
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.054 Beiträge
 
Delphi 5 Professional
 
#15

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 6. Jan 2017, 16:30
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).
PluginStartwert WSWS nach dem ersten NetzwerkkontaktEndwert nach 5 StundenDiffKommentar
alle außer External, PerfCounter, SMART, HD, SpeedFan3004318831924VM mit XP
alle außer External, PerfCounter, SMART, HD3032326855682300VM mit XP
alle außer External, PerfCounter, SMART, HD, SpeedFan?472447284Host mit Win7
alle außer External, PerfCounter, SMART, SpeedFan43244712472412Host mit Win7
alle außer External, SMART436045605132572Win2k; Wert nach 3 Stunden

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 Code des Plugins werfen. Ich werde dasselbe tun. Nach einem ersten Blick auf den Code, ist meine Vermutung, dass das Leck irgendwo in der Funktion SpeedFanNodePlugin::ListenerThread::ProcessBuffer( ) steckt.

Grüße
Dalai
  Mit Zitat antworten Zitat
nahpets

Registriert seit: 11. Okt 2006
2.408 Beiträge
 
Delphi 7 Professional
 
#16

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 6. Jan 2017, 17:04
Meine C++-Kenntnisse tendieren gegen 0.

In der von Dir genannten Routine wird in 'ner Schleife mehr oder weniger häufig
Code:
currentBlock = new xAPBlockHeader(currentPos);
bzw.
Code:
currentBlock = new xAPBlockData(currentPos);
aufgerufen. Hier wird ja wohl irgendwas neu erstellt. Was ich nicht finden kann ist die Stelle, an der wieder aufgeräumt wird.
Stephan
Weil die Lichtgeschwindigkeit höher als die Schallgeschwindigkeit ist, hält man viele Leute für helle Köpfe, bis man sie reden hört.
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
3.944 Beiträge
 
Delphi 10.1 Berlin Starter
 
#17

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 6. Jan 2017, 19:06
Aufgräumt wird später in Zeile 271, aber so wie ich das sehe wird im Block von 239 - 249 unter bestimmten Konditionen das push_back vergessen.
"Do not argue with an idiot. He will drag you down to his level and beat you with experience."
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.054 Beiträge
 
Delphi 5 Professional
 
#18

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 8. Jan 2017, 16:18
Aufgräumt wird später in Zeile 271 [...]
So ist es.

Zitat:
[...] aber so wie ich das sehe wird im Block von 239 - 249 unter bestimmten Konditionen das push_back vergessen.
Nein. Man muss hier leider ein bisschen um die Ecke denken. Der Header wird erst beim folgenden Schleifendurchlauf in die Variable blocks aufgenommen. Der letzte Datenblock folgt dann durch das push_back() nach der while-Schleife.

---

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 example2.txt), die anzeigen "ich lebe noch".

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:
} else {
    for (std::vector<xAPBlock *>::iterator it = blocks.begin(); it != blocks.end(); it++)
      delete *it;
}
um alle Objekte in blocks wieder aufzuräumen. Das sollte alle nötigen Fälle abdecken.

Ob's das wirklich ist (und das einzige Leck), wird sich zeigen.

Grüße
Dalai

Geändert von Dalai ( 8. Jan 2017 um 16:21 Uhr)
  Mit Zitat antworten Zitat
Delphi-Laie

Registriert seit: 25. Nov 2005
1.222 Beiträge
 
Delphi 10.1 Berlin Starter
 
#19

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 8. Jan 2017, 17:44
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 diese Dokumentation dazu lesen.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.054 Beiträge
 
Delphi 5 Professional
 
#20

AW: Speicherlecks in fremdem Code/Programm finden

  Alt 10. Jan 2017, 21:57
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:
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;
  ...
}
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.

Danke an alle Beteiligten!

Grüße
Dalai
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:11 Uhr.
Powered by vBulletin® Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2017 by Daniel R. Wolf