Wie oft unterläuft euch ein Memleak?



  • Xin schrieb:

    RAII ist eine sinnvolle Möglichkeit, aber keine Antwort auf alle Probleme, ansonsten hätten Garbage Collections überhaupt keine Diskussionsgrundlage.

    Tja.. ehm.. du hast da schon irgendwo etwas erkannt. 😃



  • Xin schrieb:

    Das liest sich hier, als wäre RAII eine allumfassende Antwort auf alle Probleme.

    Das wollte ich damit sagen.



  • @Xin
    Zum Programmieren braucht man immer ein Gehirn, und darf es auch nie ausschalten.
    RAII ist nur - für mich - wirklich eine einzelne Sache die ungleich mehr bringt als vieles was es sonst noch an "good practices" gibt.

    Natürlich gibt es auch mit RAII Fälle wo die Dinge anfangen etwas kompliziert zu werden.
    Diese Fälle sind aber nach meiner Erfahrung ausreichend selten. Wenn ich hin und wieder gut aufpassen muss was ich mache, ist das für mich kein echtes Problem. Wenn ich dagegen bei jeder Zeile aufpassen muss wie ein Haftelmacher ermüde ich viel zu schnell, und fange dann an Fehler zu machen. Und/oder vergleichsweise sehr sehr langsam zu werden.

    Und was mein "seit RAII quasi keine Leaks mehr" Statement angeht: das ist einfach ne Beobachtung. Meine Konzentrationsfähigkeit ist heute eher schlechter als noch vor 10 Jahren. Wenn ich trotzdem heute deutlich weniger Leaks produziere als damals, kann es also fast nur daran liegen dass ich heute irgendwas grundsätzlich anderes mache. z.B. andere Patterns/Idioms verwenden.



  • kellerassel: leak mir am arsch 😋 😋



  • Die einzige Existenzberechtigung von GCs ist doch, dass sie unter Umständen schneller sein können. Zb wenn es viele kleine Allocations gibt die aufgeräumt werden müssen, zb in Java.



  • hustbaer schrieb:

    @Xin
    Zum Programmieren braucht man immer ein Gehirn, und darf es auch nie ausschalten.
    RAII ist nur - für mich - wirklich eine einzelne Sache die ungleich mehr bringt als vieles was es sonst noch an "good practices" gibt.

    Das kann man ohne Zweifel so stehen lassen.

    hustbaer schrieb:

    Natürlich gibt es auch mit RAII Fälle wo die Dinge anfangen etwas kompliziert zu werden. Diese Fälle sind aber nach meiner Erfahrung ausreichend selten.

    Bäume? Listen?

    hustbaer schrieb:

    Wenn ich hin und wieder gut aufpassen muss was ich mache, ist das für mich kein echtes Problem. Wenn ich dagegen bei jeder Zeile aufpassen muss wie ein Haftelmacher ermüde ich viel zu schnell, und fange dann an Fehler zu machen. Und/oder vergleichsweise sehr sehr langsam zu werden.

    Dafür fängt man ggfs. aber an, viel zu kopieren, z.B. wenn man Objekte dann in Vectoren packt.

    hustbaer schrieb:

    Und was mein "seit RAII quasi keine Leaks mehr" Statement angeht: das ist einfach ne Beobachtung. Meine Konzentrationsfähigkeit ist heute eher schlechter als noch vor 10 Jahren. Wenn ich trotzdem heute deutlich weniger Leaks produziere als damals, kann es also fast nur daran liegen dass ich heute irgendwas grundsätzlich anderes mache. z.B. andere Patterns/Idioms verwenden.

    Okay, das ist eine subjektive Erfahrung (die ich zwar in ähnlicher Form teile), aber halt keine Garantie.

    --------------

    Ethon schrieb:

    Die einzige Existenzberechtigung von GCs ist doch, dass sie unter Umständen schneller sein können. Zb wenn es viele kleine Allocations gibt die aufgeräumt werden müssen, zb in Java.

    Allocations sind in Java nur dann schneller, wenn man in C++ nicht poolt.

    Man hat also durchaus Einfluss auf die Umstände. Beim Freigeben ist C++ dann wieder schneller. Der Umstand ist also auch stark davon abhängig, ob das Programm zwischendurch überhaupt den GC benutzt oder einfach nur solange Speicher verteilt, bis am Ende einfach alles jemals genutzte am Stück freigegeben wird.
    Das ist natürlich schnell... aber Speicheraufwendig.



  • Ethon schrieb:

    Die einzige Existenzberechtigung von GCs ist doch, dass sie unter Umständen schneller sein können. Zb wenn es viele kleine Allocations gibt die aufgeräumt werden müssen, zb in Java.

    Das kannst du in C++ ganz leicht global (Allokationsoperatoren überschreiben), oder lokal (eigene Allokatoren nutzen) kontrollieren. Und das genau abgestimmt auf deine Wünsche. Zudem legt man viele kleine Objekte eher auf dem Stack an (was einem GC weit überlegen ist, viele kleine Objekte sind eigentlich oft das Paradebeispiel für das Versagen von GCs), oder reserviert gleich viel Speicher. Jedenfalls hat man alle Möglichkeiten die ein GC hat, außer Speicher umräumen.



  • kellerkindanwärter schrieb:

    kellerassel: leak mir am arsch 😋 😋

    bist du so gelenig? 😮



  • _D_D schrieb:

    kellerkindanwärter schrieb:

    kellerassel: leak mir am arsch 😋 😋

    bist du so gelenig? 😮

    +k 🙄
    gelenkig wollte ich natürlich schreiben



  • Ausgewaehlte* Statements aus den ersten Antworten:

    Selten bis nie, RAII ftw ... bevor ich (vor vielen jahren) angefangen habe RAII zu verwenden hatte ich hin und wieder mal leaks ... haben wir seit konsequenter Anwendung von RAII - i.A. in Form eines Smart-Pointers - genau NULL Probleme ... wei C++ mit RAII keinen Carbage macht ...

    Das hat mich irgendwie an schlechte Werbung fuer Putzmittel oder Waschmittel erinnert. Das klingt so, als koenne man nicht Wasche waschen, wenn Persil oder Spee fehlt. Klar ist die vollautomatische Waschmaschine besser als das Scheuerbrett, eine Wahl faellt dabei nicht schwer. Ja gebt mir all die netten Sachen, aber gegen das Meer aus ... schlechter Software kann ich damit wenig ausrichten. Wo kommt all der schlechte Code her?

    Dann zur Sache mit dem Neuschreiben: Angenommen mir wird die Zeit gegeben, angenommen ich werde dafuer bezahlt. Angenommen ich habe eine neues funktionierendes Progr ... erstmal nur ein Programm. Angenommen es besteht auch die Tests. Was halte ich dann in den Haenden? Von aussen betrachtet hat es keinen Mehrwert, bis jetzt hat es nur Kosten verursacht, damit der Entwickler ... ruhiger schlafen kann? Vielleicht zahlt es sich in spaeteren Jahren aus, vielleicht auch nicht. Ungewiss!

    Und wie macht man das deiner Meinung nach am besten?

    Durch Disziplin! Aber mal ehrlich, ich glaube kaum, dass ihr aufgeschmissen seid, wenn ein Aspekt der Sprache wegfaellt. Keine Templates -> eigener Codegenerator, Kein RAII -> na dann wie in C, keine smart_pointer -> dann eben per Hand, kein std::move -> mittels Flag und Kopierkonstrukter . Was haben all die Leute gemacht, als es noch kein C++ gab, die C, Fortran, Pascal ... benutzten? Die waren ja komplett aufgeschmissen.

    Ethon schrieb:

    Die einzige Existenzberechtigung von GCs ist doch, dass sie unter Umständen schneller sein können. Zb wenn es viele kleine Allocations gibt die aufgeräumt werden müssen, zb in Java.

    Ja, die bessere Performance hat den Siegeszug von .Net und Java eingelaeutet. Waehrend C++ noch mit seine RAIIfen beschaeftigt ist, duest Java einfach davon. Nee, mal im Ernst: die Implementation bei manchen lock-free Algorithmen soll einfacher sein. Habe das Geruecht aber nicht weiter verfolgt. Irgend wo bei GoingNative gefallen. Auch sind die Programmierer fuer solche Sprachen billiger. Ok, Lisp, Haskell, ML sind wohl Ausnahmen. Warum die wohl einen GC haben ... . Zumindestens in Scheme gibt es auch RAII speziell fuer Dateien.

    *von mir mit einer Absicht



  • Xin schrieb:

    Das liest sich hier, als wäre RAII eine allumfassende Antwort auf alle Probleme.

    RAII ist die einzige gute Antwort auf Ressourcenmanagement, die ich kenne. Das heißt nicht, dass es nicht andere Wege gibt. Garbage Collection ist jedenfalls kein solcher. Garbage Collection ist imo ein fundamentaler Designfehler, der leider mal eine Zeit lang extrem modern war und mit dem wir heute in manchen Sprachen daher leider leben müssen. So ähnlich wie z.B. der Missbrauch des Singleton Pattern auch...

    Xin schrieb:

    Obwohl ich RAII ebenfalls sehr gerne verwende, bleibe ich aber auch den Pointern treu.

    RAII ist kein Ersatz für Pointer. RAII ist eine Lebenseinstellung...

    Xin schrieb:

    RAII ist eine sinnvolle Möglichkeit, aber keine Antwort auf alle Probleme, [...]

    Natürlich nicht. RAII ist aber die mit großem Abstand beste bekannte Antwort auf so ziemlich alles, was mit Ressourcenmanagement zu tun hat...

    Xin schrieb:

    [...] ansonsten hätten Garbage Collections überhaupt keine Diskussionsgrundlage.

    Ich kenn kein vernünftiges Argument für Garbage Collection, kennst du eins? Garbage Collection ermuntert imo zu schlechtem Design, der GC nimmt einem die Sicht auf viele fundamentale Probleme (die sind natürlich trotzdem noch da, nur merkt mans erst, wenns schon zu spät ist). Ja, solange man erstmal nur schnell irgendwelche Benutzeroberflächen zusammenklicken will, ohne irgendeine Form von anspruchsvoller Logik dahinter, ist man mit GC evtl. anfangs wesentlich schneller, weil viele Dinge, über die man sich eigentlich Gedanken machen müsste, einfach hinter einem komplexen globalen Mechanismus versteckt werden können. Sobald man aber an einen bestimmten Punkt kommt, zeigt sich plötzlich, wie kaputt alles in Wirklichkeit doch ist, das Kartenhaus bricht zusammen und man verbringt ab da die meiste Zeit nun damit, Dinge mit Klebeband zusammenzupappen und Wege zu finden, um den globalen Mechanismus zu überlisten...

    Xin schrieb:

    Auch mit RAII darf man den Verstand nicht einfach ausschalten, denn dass sich ''new'' mit RAII komplett ersetzen lässt ist nicht zwangsläufig gegeben.

    Bist du dir sicher, dass du RAII richtig verstanden hast? 😉



  • cooky451 schrieb:

    Jedenfalls hat man alle Möglichkeiten die ein GC hat, außer Speicher umräumen.

    Wer sagt denn sowas? ^^

    Du musst lediglich statt Pointer Java-Artige-Referenzen verwenden.



  • Garbage Collection ist imo ein fundamentaler Designfehler ... Ich kenn kein vernünftiges Argument ...

    Hmm, wenn ich an (funktionale) Sprachen denke im allgemeinen und an echte Continuations im speziellen (nicht setjmp/longjmp)... also ich wuerde das so nicht unterschreiben. Ohne Garbage Collector wohl die Hoelle auf Erden. Ich kenne keine halbwegs funktionale Sprache ohne Garbage Collector. Auch der Vergleich mit dem Userinterface ... hmm ... Nein!



  • Xin schrieb:

    hustbaer schrieb:

    Natürlich gibt es auch mit RAII Fälle wo die Dinge anfangen etwas kompliziert zu werden. Diese Fälle sind aber nach meiner Erfahrung ausreichend selten.

    Bäume? Listen?

    Sehe ich jetzt nicht als Problem.
    Vielleicht verstehst du unter RAII auch was anderes als ich. Wenn ich RAII schreibe meine ich bloss dass jede Resource bzw. jedes dynamisch erzeugte Objekt zu jedem Zeitpunkt von genau einem anderen Objekt "kontrolliert" wird, und dieses sich im Destruktor um die Freigabe kümmert.
    Das muss nicht heissen dass die Besitzverhältnisse nicht wechseln können, oder dass ein Objekt nur genau ein anderes kontrollieren darf.

    Bei Listen besitzt z.B. einfach die Liste alle Nodes. Wenn man Nodes "ausklinken" will kann man sie entweder ala std::list in eine neue Liste raustrennen, oder einfach nen std::unique_ptr (bzw. vor C++11 einen std::auto_ptr) zurückgeben.

    Bei Bäumen kann entweder der Baum alle Nodes besitzen, oder der Baum besitzt die Root-Node, und alle Nodes besitzen ihre unmittelbaren Kinder.

    Klar muss man dabei aufpassen während man die Liste oder den Baum selbst implementiert, aber bei der Verwendung muss man sich dann keine Sorgen mehr machen dass irgendwas nicht oder doppelt freigegeben werden könnte.

    Und das ist für mich in Summe dann "ausreichend selten". Zumindest ich implementiere wesentlich weniger oft Datenstrukturen als ich sie dann verwende. (Und meist komme ich sowieso mit den vorgegebenen Datenstrukturen der STL bzw. Boost aus.)

    hustbaer schrieb:

    Wenn ich hin und wieder gut aufpassen muss was ich mache, ist das für mich kein echtes Problem. Wenn ich dagegen bei jeder Zeile aufpassen muss wie ein Haftelmacher ermüde ich viel zu schnell, und fange dann an Fehler zu machen. Und/oder vergleichsweise sehr sehr langsam zu werden.

    Dafür fängt man ggfs. aber an, viel zu kopieren, z.B. wenn man Objekte dann in Vectoren packt.

    Was manchmal auch vollkommen OK ist, weil 80/20 und so.
    Bei den "20% des Codes" Stellen muss man dann halt wieder sein Hirn einschalten wenn das viele Kopieren zu einem Problem wird. Aber auch nicht bei jeder Zeile Code, siehe oben.

    hustbaer schrieb:

    Und was mein "seit RAII quasi keine Leaks mehr" Statement angeht: das ist einfach ne Beobachtung. Meine Konzentrationsfähigkeit ist heute eher schlechter als noch vor 10 Jahren. Wenn ich trotzdem heute deutlich weniger Leaks produziere als damals, kann es also fast nur daran liegen dass ich heute irgendwas grundsätzlich anderes mache. z.B. andere Patterns/Idioms verwenden.

    Okay, das ist eine subjektive Erfahrung (die ich zwar in ähnlicher Form teile), aber halt keine Garantie.

    Ja, klar. Im Endeffekt sind das doch alles nur subjektive Erfahrungen bzw. Meinungen.



  • cooky451 schrieb:

    Ethon schrieb:

    Die einzige Existenzberechtigung von GCs ist doch, dass sie unter Umständen schneller sein können. Zb wenn es viele kleine Allocations gibt die aufgeräumt werden müssen, zb in Java.

    Das kannst du in C++ ganz leicht global (Allokationsoperatoren überschreiben), oder lokal (eigene Allokatoren nutzen) kontrollieren. Und das genau abgestimmt auf deine Wünsche. (...)

    Wenn man in C++ leicht irgendwas sinnvolles machen kann, indem man global operator new/delete überschreibt, dann hat die C++ Implementierung die man verwendet einen furchtbar miesen Allokator.
    Und lokal ist das auch nur in wenigen Fällen sinnvoll möglich.

    Was in C++ z.B. teuer ist, und kaum nicht-teuer zu bekommen, ist thread-safe shared ownership.
    Man kann oft drum rumarbeiten, sein Programm anders designen so dass man keine thread-safe shared ownership mehr braucht. Wenn man es aber nicht kann, dann kann eine GC-Implementierung hier schon die Nase vorn haben. Ein klassischer "stop the world" Collector erlaubt nämlich ganz stinknormale Zuweisungen statt teure atomare acquire/release Operationen zu verwenden.



  • In der Tat, wenn man es mit extrem parallelen Architekturen zu tun hat (z.B. GPUs), hat GC potentielle Vorteile gegenüber einer klassischen manuellen Speicherverwaltung.
    Wobei ich nicht glaube, dass man dort unbedingt vollwertige Garbage Collection haben will. Der Knackpunkt ist das explizite delete. In einer extrem parallelen Umgebung ist ein explizites delete tatsächlich sehr kompliziert bzw. problematisch zu supporten.
    Imo funktioniert aber schon das Konzept von malloc()/free() bzw. eben new/delete an sich dort einfach nicht wirklich gut. Der Grund dafür liegt in der Natur der entsprechenden Hardware und Anwendungen. Ich denk jedenfalls, dass dort überhaupt grundlegend neue Konzepte gefragt sind, GC ist einfach von den bekannten Konzepten jener Fisch, der etwas schneller über das neue Land zappeln kann.
    In jedem Fall sind das Spezialanwendungen und ich finde eine weitaus sinnvollere Herangehensweise, als GC gleich mal ins Fundament einer Sprache zu gießen, ist eine der Anwendung entsprechende Speziallösung in Form einer Library. Ich bin mittlerweile sogar fast der Meinung, dass auch new und delete in ihrer jetzigen Form nicht Teil einer Sprache sein sollten (eine Erkenntnis, die ich Krishty zu verdanken hab). Eine Sprache sollte rein nur eine Möglichkeit bieten, Objekte zu konstruieren und wieder zu zerstören. Speicher besorgen und wieder zurückgeben, sollte explizit Aufgabe einer Library sein...



  • dot schrieb:

    Ich bin mittlerweile sogar fast der Meinung, dass auch new und delete in ihrer jetzigen Form nicht Teil einer Sprache sein sollten (eine Erkenntnis, die ich Krishty zu verdanken hab). Eine Sprache sollte rein nur eine Möglichkeit bieten, Objekte zu konstruieren und wieder zu zerstören. Speicher besorgen und wieder zurückgeben, sollte explizit Aufgabe einer Library sein...

    Naja...
    Im Prinzip macht C++ das ja auch so. Nur dass das Interface etwas unglücklich gewählt wurde. DAS finde ich schade, aber vom Prinzip her ist es mMn. schon OK.

    Wenn man es sich wirklich antun will, dann gibt es auch noch placement new, und als Ersatz für das fehlende placement delete darf man Destruktoren direkt aufrufen, und den Speicher danach selbst freigeben.
    (Wobei es "placement delete" strenggenommen sogar gibt, wird aber nur automatisch vom Compiler aufgerufen wenn eine Exception in einem per "placement new" aufgerufenen Konstruktor fliegt.)

    Man kann sich also jederzeit seine eigenen "new"/"new []" sowie "delete"/"delete []" Funktionen (Templates) schreiben.



  • hustbaer schrieb:

    Im Prinzip macht C++ das ja auch so. Nur dass das Interface etwas unglücklich gewählt wurde.

    Ja, das Interface ist imo in der Tat sehr unglücklich gewählt...

    hustbaer schrieb:

    Man kann sich also jederzeit seine eigenen "new"/"new []" sowie "delete"/"delete []" Funktionen schreiben.

    Theoretisch ja, in der Praxis ist das aber, aufgrund des unglücklich gewählten Interface, potentiell problematisch. Ich denk da z.B. an so Dinge, wie das Sicherstellen, dass auch überall im Programm die richtigen Versionen der Funktionen bekannt sind und verwendet werden...



  • Xin schrieb:

    kellerassel schrieb:

    hab grad wieder einen gefunden 😃

    Ausgesprochen selten, wobei mich das das selbst wundert.

    Gelegentlich mit valgrind gegentesten.

    mach ich schon, aber das langweilt mich, mysql und die c++ lib die ich verwende werfen ständig fehler und dann muss man ewig scrollen 😞



  • axo, bei mysql schauts so aus...

    ==20468== Conditional jump or move depends on uninitialised value(s)
    ==20468==    at 0x4063A2E: inflateReset2 (in /usr/lib/libz.so.1.2.3.4)
    ==20468==    by 0x4063B0C: inflateInit2_ (in /usr/lib/libz.so.1.2.3.4)
    ==20468==    by 0x4063B82: inflateInit_ (in /usr/lib/libz.so.1.2.3.4)
    ==20468==    by 0x405E34E: uncompress (in /usr/lib/libz.so.1.2.3.4)
    ==20468==    by 0x4333474: my_uncompress (in /usr/lib/libmysqlclient.so.16.0.0)
    ==20468==    by 0x435E88E: my_net_read (in /usr/lib/libmysqlclient.so.16.0.0)
    ==20468==    by 0x4358323: cli_safe_read (in /usr/lib/libmysqlclient.so.16.0.0)
    ==20468==    by 0x4358AC4: ??? (in /usr/lib/libmysqlclient.so.16.0.0)
    ==20468==    by 0x43240BB: mysql_next_result (in /usr/lib/libmysqlclient.so.16.0.0)
    ...
    

Anmelden zum Antworten