Speicherimplosion, Calloc/Free, Memory leaks
-
Tach,
ich habe eine Frage, die hier schon mal diskutiert aber leider nicht beantwortet wurde (vgl. http://www.c-plusplus.net/forum/viewtopic.php?t=70829&highlight=memory+leak).
"Gibt es ein Tool, mit dem man zur Laufzeit sehen/loggen kann, welche Variablen 1.) überhaupt existieren, und 2.) wieviel Speicher sie benötigen ? Hab meinen Quellcode schon dreimal überarbeitet und hab zu jedem calloc ein free. Dennoch explodiert der Verbrauch... Welche Gründe könnte das noch haben ?"
Ja, ich habe schon bei Google gesucht. Nein, memory leaks u.ä. müssen nicht unbedingt vorliegen, das prg erzeugt keine Zugriffsverletzungen und wenn es fertig ist, gibt es den Speicher brav wieder frei. Nein, das Problem scheint nicht vom Compiler abzuhängen. Ja, natürlich ist mein Algorithmus verbesserungswürdig.
Im Wesentlichen wird die Arbeit von Funktionen getan, die als Argument(e) und als Wert jeweils pointer auf structs (die v.a. als Hülle für Vektoren von structs dienen) haben, also alles call-by-ref (?). Eine Ausnahme von der calloc-free-Bijektion bilden die Return-Werte der Funktionen. Deren Speicher wird innerhalb der jeweiligen Funktion alloziiert, und kann natürlich nicht vor dem return freigegeben werden (aber doch wohl danach, "automatisch" ?).Meine Frage bezieht sich auf ANSI C.
Danke,
Sascha.
-
tiruvarur schrieb:
Meine Frage bezieht sich auf ANSI C.
Dann ist sie hier falsch.
-
hast du dir nicht Valgrind angeguckt? Das ist ein Tool zum kontrollieren von Speicherverbrauch und co
-
tiruvarur schrieb:
"Gibt es ein Tool, mit dem man zur Laufzeit sehen/loggen kann, welche Variablen 1.) überhaupt existieren
Sicher nicht. Es gibt zur Laufzeit keine "Variablen" mehr. Alles andere ist build-abhängig und kommt darauf an, wieviele Infos (zB Debug-Infos) in die Executable aufgenommen wurden.
tiruvarur schrieb:
und 2.) wieviel Speicher sie benötigen ?
siehe oben
tiruvarur schrieb:
Nein, memory leaks u.ä. müssen nicht unbedingt vorliegen, das prg erzeugt keine Zugriffsverletzungen
Was du hier machst ist spekulieren. Damit kommst du nicht weiter. Um Memory Leaks auszuschliessen, könntest du eigene *alloc/free Funktionen schreiben, welche den Speicherverbrauch loggen. Oder du nimmst ein externes Tool (zB valgrind). Und Zugriffsverletzungen müssen auch nicht zwangsläufig auftreten bei fehlerhaftem Speichermanagement.
tiruvarur schrieb:
und wenn es fertig ist, gibt es den Speicher brav wieder frei.
Woher hast du diese Erkenntnis?
tiruvarur schrieb:
Eine Ausnahme von der calloc-free-Bijektion bilden die Return-Werte der Funktionen. Deren Speicher wird innerhalb der jeweiligen Funktion alloziiert und kann natürlich nicht vor dem return freigegeben werden
Das ist so ziemlich das schlimmste was du machen kannst. Gerade in C solltest du immer darauf achten, *alloc/free auf einer Ebene zu handeln. Das steigert die Wartbarkeit des Codes in jedem Fall.
tiruvarur schrieb:
(aber doch wohl danach, "automatisch" ?).
Nicht "automatisch". Darum musst du dich schon selbst kümmern.
-
@kingruedi: meine Produktivumgebung ist xp, aber wenn Valgrind sooo gut ist, werde ich mal meine Suse-Partition reanimieren.
groovemaster schrieb:
tiruvarur schrieb:
"Gibt es ein Tool, mit dem man zur Laufzeit sehen/loggen kann, welche Variablen 1.) überhaupt existieren
Sicher nicht. Es gibt zur Laufzeit keine "Variablen" mehr.
Aber ich habe doch mit eigenen Augen gesehen, wie z.B. der Debugger von lcc "zur Laufzeit" die Belegung und die Adressen gewisser Variablen anzeigt ?! Solches Output wünsche ich mir für alle Variablen über die gesamte Laufzeit.
groovemaster schrieb:
tiruvarur schrieb:
und wenn es fertig ist, gibt es den Speicher brav wieder frei.
Woher hast du diese Erkenntnis?
Diverse Taskmanager zeigen mir doch den Verlauf von RAM, Swap etc. in Abhängigkeit von der Zeit.
groovemaster schrieb:
tiruvarur schrieb:
Eine Ausnahme von der calloc-free-Bijektion bilden die Return-Werte der Funktionen. Deren Speicher wird innerhalb der jeweiligen Funktion alloziiert und kann natürlich nicht vor dem return freigegeben werden
Das ist so ziemlich das schlimmste was du machen kannst. Gerade in C solltest du immer darauf achten, *alloc/free auf einer Ebene zu handeln.
Ich mache in etwa folgendes:
MeineStruct *ms; ms=funktion(....);
mit der Funktion
MeineStruct *funktion(...) {MeineStruct *returnwert=(MeineStruct *)malloc(4711*sizeof(MeineStruct)); //... // hier gibt es die calloc-free-Bijektion return returnwert; }
Mein *alloc/free-Handling findet immer auf einer Ebene statt. Die Frage ist, was nach dem return mit "returnwert" passiert. Ich wähnte, dessen Speicher wird dann freigegeben.
-
tiruvarur schrieb:
groovemaster schrieb:
tiruvarur schrieb:
"Gibt es ein Tool, mit dem man zur Laufzeit sehen/loggen kann, welche Variablen 1.) überhaupt existieren
Sicher nicht. Es gibt zur Laufzeit keine "Variablen" mehr.
Aber ich habe doch mit eigenen Augen gesehen, wie z.B. der Debugger von lcc "zur Laufzeit" die Belegung und die Adressen gewisser Variablen anzeigt ?!
Hast du dir den Abschnitt von mir ganz durchgelesen? Dies ist wie gesagt build-abhängig. Der Debugger kann sowas anzeigen, weil entsprechende Debug-Infos mit in die Executable aufgenommen wurden. Das ist aber von Compiler zu Compiler unterschiedlich. Der Normalfall für Release Versionen ist aber, dass die Executable gar keine Debug Infos hat. Vielleicht ist es möglich in deinem speziellen Fall was mit den Debug Infos zu machen. Who knows. Nutzen und Aufwand stehen da aber sicherlich in keinem Verhältnis.
Ich versteh auch nicht, warum du überhaupt solche Sachen machen willst. Welche Variablen es gibt, siehst du doch im Quellcode. Und wieviel Speicher jede Variable belegt auch. Das einzige was du nicht weisst sind die dynamisch reservierten Speicherbereiche. Sowas kann man aber wie gesagt leicht mit eigenen *alloc/free Funktionen loggen.tiruvarur schrieb:
Diverse Taskmanager zeigen mir doch den Verlauf von RAM, Swap etc. in Abhängigkeit von der Zeit.
Sowas sagt noch überhaupt nichts aus. Moderne BS geben in der Regel den vom Prozess angeforderten Speicher bei dessen Ende automatisch frei. Dies ist aber keine Freikarte, kein sauberes Ressourcenmanagement zu betreiben. Such mal hier im Forum, darüber gab es schon einige Threads.
tiruvarur schrieb:
Mein *alloc/free-Handling findet immer auf einer Ebene statt.
Das belegen aber weder deine Aussagen, noch dein Beispiel.
tiruvarur schrieb:
Die Frage ist, was nach dem return mit "returnwert" passiert.
Was soll denn damit schon passieren? Es ist einfach ein Zeiger auf einen reservierten Speicherbereich, der da zurückgegeben wird. Letztendlich ist das nichts anderes als ein stinknormaler Adresswert. C/C++ betreibt ja glücklicherweise kein Garbage Collecting. Das bedeutet aber auch, dass jeder angeforderter Speicherbereich auch explizit wieder freigegeben werden muss. Grob kannst du dir merken, dass es für jedes *alloc auch ein free geben muss. Wobei du in C++ mit Smart Pointer Klassen noch mehr Möglichkeiten hast.
-
Danke, v.a. an groovemaster. Ich hatte tatsächlich gegen die behauptete *alloc-free-Bijektion verstossen.