Ursachen Memoryleaks in .NET



  • Sorry, je mehr ich drüber nachdenke, desto unsinniger kommt mir diese Philosophie vor.

    Zudem, der Speicher wird automatisch vom GC freigegeben. Die Objekte aber nicht.

    Was soll das bedeuten? Es gibt sowas wie "Objekt freigeben" überhaupt nicht. Das ist begrifflicher Unsinn.

    Das was du so nennst, nämlich Referenzen lösen, betrifft auch überhaupt keine Objekte, sondern Referenzen. Es ist den Objekten sogar völlig gleichgültig, ob du irgendwo Referenzen löst.

    Und zu "Ich hole nichts rein." Doch, hast du selbst geschrieben. Du bist der Meinung, eine hierarchische Besitzstruktur haben zu müssen. Du hast dir also eine künstliche Beschränkung auferlegt. Dabei bringt Hierarchie überhaupt keine Vorteile, ein GC kann mit Zyklen genauso gut umgehen.


  • Administrator

    Bashar schrieb:

    Sorry, je mehr ich drüber nachdenke, desto unsinniger kommt mir diese Philosophie vor.

    Das ist dein gutes Recht 🙂
    Aber meiner Meinung nach überinterpretierst du meine Aussagen.

    Bashar schrieb:

    Und zu "Ich hole nichts rein." Doch, hast du selbst geschrieben. Du bist der Meinung, eine hierarchische Besitzstruktur haben zu müssen. Du hast dir also eine künstliche Beschränkung auferlegt. Dabei bringt Hierarchie überhaupt keine Vorteile, ein GC kann mit Zyklen genauso gut umgehen.

    Hier ist z.B. so eine Überinterpretierung drin. Ich habe nirgends gesagt, dass ich mich auf eine hierarchische Besitzstruktur einschränke. Ich sagte nur, dass diese das Problem meistens automatisch löst. Und schau mal deine Programme an, wieviel hierarchische Besitzstruktur darin vorkommt.
    Ich verwende aber auch andere Arten von Besitzstrukturen. Nur passe ich dann besser auf.

    Wenn du sagst, dass der GC auch mit Zyklen genauso gut umgehen kannst, dann stimme ich dir zwar teilweise zu. Du hast aber dabei eine Überlegung vergessen zu machen. Dieser Zyklus, welcher der GC nun freigibt, wurde von irgendjemandem besessen.

    Ich kann mich nur nochmals wiederholen, überinterpretiere meine Aussagen nicht. Es ist einfach nur ein etwas anderer Denkansatz. Man könnte vielleicht auch sagen, dass ich einfach nur bewusst mit dem GC zusammenarbeite. Und zusammenarbeiten heisst, dass ich mir z.B. auch sehr wohl bewusst bin, dass der GC Zyklen freigeben kann.

    Grüssli



  • Ich mache mir in .NET ehrlich gesagt nur selten Gedanken über Speicher als Resource. Alles was geht, wird in using gepackt und das Thema ist damit abgehakt. Der Rest ist meistens eh nur lokal im Scope.



  • GPC schrieb:

    Ich mache mir in .NET ehrlich gesagt nur selten Gedanken über Speicher als Resource. Alles was geht, wird in using gepackt und das Thema ist damit abgehakt. Der Rest ist meistens eh nur lokal im Scope.

    Oh du Glücklicher...für mich war ein GC bisher praktisch immer mehr Bürde als sonst was...



  • Hmm, bedeutet dies, dass im folgender Situation:

    void Scope()
    {
       var tmp = new MemoryStream(..);
    
       ........
    }
    

    das MemoryStream Objekt zwar am ende eine NULL Referenz hat, da der Scope verlassen wird, aber durch NICHT aufrufen von Dispose, das Objekt nich freigegeben wird?

    GRüße



  • Hier existiert ein gros

    NullBockException schrieb:

    das MemoryStream Objekt zwar am ende eine NULL Referenz hat, da der Scope verlassen wird, aber durch NICHT aufrufen von Dispose, das Objekt nich freigegeben wird?
    GRüße

    Das Objekt wird auch nicht freigegeben, sondern die Resourcen die das Objekt verwaltet.



  • Kommt drauf an.
    Es kann sein dass nichtverwalteter Speicher oder eine Betriebssystemressource nicht freigegeben wird oder etwas anderes nicht sauber aufgeräumt wird. Beispiel: Ein Wrapper für Bitmaps der die Pixel im Konstruktor lockt und in der Dispose-Methode wieder freigibt.

    Kann praktisch alles mögliche sein. Deshalb: Der Entwickler einer Klasse die IDisposable implementiert, hat sich etwas dabei gedacht und deshalb sollte Dispose immer wenn angeboten aufgerufen werden.



  • das bedeutet? sorry versteh ich nich !



  • NullBockException schrieb:

    das bedeutet? sorry versteh ich nich !

    Was verstehst du nicht?



  • NullBockException schrieb:

    das bedeutet? sorry versteh ich nich !

    IDisposable da? myObject.Dispose() schreiben.
    IDisposable nicht da? Eierschaukeln.



  • Das bedeutet, dass Garbage Collection dich vor Memory Leaks schützt. Und der Preis dafür ist, dass jede andere Art von Ressource praktisch unmöglich zu verwalten wird...



  • Hmm ok verstehe, schön wäre es, wenn der ReSharper mir die Stellen iwürde, an denen ich ein mögliches Dipsose nich aufgerufen habe:)





  • Funktioniert offenbar aber nur für lokale Disposable Objekte und die sind kaum ein Problem, weil da kann man using machen und gut ist. Lustig wirds mit Disposable Membern...



  • dot schrieb:

    Lustig wirds mit Disposable Membern...

    Die sind oft ein guter Hinweis, dass die enthaltende Klasse ebenfalls IDisposable implementieren sollte. In solchen Fällen zieht es sich bis zur Wurzel und ist kein Problem mehr.



  • Ich sehe auch nicht, wieso Member, die man disposen muss, ein Problem darstellen. Dann geht man halt hin und spendiert seiner Klasse selbst Dispose, wo man dann wiederum das Dispose der Member aufruft. Klingt gut. Hab ich was übersehen?



  • Hier scheint ein falsches Verständnis von Dispose vorzuliegen. Unabhängig davon ob man nun using benutzt oder Dispose manuell aufruft ist garantiert das Dispose ausgeführt wird, weil dieses im Finalizer sichergestellt wird. Wurde es vorher nicht manuell aufgerufen wird Dispose spätestens im Finalizer ausgeführt.

    Es geht hier allein um den Zeitpunkt wann Disposed werden soll. Auch hat es nur indirekt mit unmanaged Resourcen zu tuen. Relevant ist Dispose für stark begrenzte Resourcen. Klar sind alle Resourcen in einem Computer endlich, aber manche sind halt so stark begrenzt das man sie so schnell wie möglich wieder freigeben will sobald man sie nicht mehr braucht. (z.B. Filehandles, Grafikhandles etc)

    Und genau hier steht das Grundprizip der GC im Widerspruch, weil Objekte "irgendwann" abräumt werden. Viele unterliegen der Fehlannahme das eine GC Objekte abräumt wenn die nicht mehr gebraucht werden. Das stimmt aber so nicht. Objekte, die nicht mehr gebraucht werden räumt die GC erst dann ab wenn sie nicht mehr genug Freispeicher hat. Das kann zu einem sehr späten Zeitpunkt passieren.

    Gerade für stark begrenzte Resouecen ist das aber sehr schlecht, weil hier für einen beliebigen, unbestimmbaren Zeitraum dann eine Resource gebunden bleibt obwohl sie längst nicht mehr gebraucht würde.

    Um dieses Problem zu lösen gibt es das Dispose-Pattern. Mit Dispose() kann der Programmierer den Zeitpunkt bestimmen zu dem die begrenzten Resourcen eines Objekts freigegeben werden. Das Objekt selber wird danach immer noch von der GC abgeräumt zu einem beliebigen, späteren Zeitpunkt.

    Natürlich stimmt es also das man Dispose immer aufrufen sollte, aber nicht, weil man sonst ein Resourceleak hätte, sondern weil man sonst eher in Probleme mit begrenzten Resourcen laufen kann.



  • loks schrieb:

    Hier scheint ein falsches Verständnis von Dispose vorzuliegen. Unabhängig davon ob man nun using benutzt oder Dispose manuell aufruft ist garantiert das Dispose ausgeführt wird, weil dieses im Finalizer sichergestellt wird. Wurde es vorher nicht manuell aufgerufen wird Dispose spätestens im Finalizer ausgeführt.

    Das wusste ich noch nicht, steht das im Standard oder gibts da eine Doku zu? Wuerde das gerne nachlesen.



  • Sprich, der GC ruft die Dispose funktion auf, wenn sie nich schon aufgerufen wurde, allerdings nich deterministisch zu den object/reference scops!?



  • Hab gerade mal hier geschaut:
    http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf

    Punkt 17.12 Finalizer. Da hab ich nichts dergleichen gefunden. loks, hast du da andere Quellen?


Anmelden zum Antworten