Anatomie eines "Memory Leak"

  • In der .NET-Perspektive:

    • Was ist ein Speicherverlust ?
    • Wie können Sie feststellen, ob Ihre Anwendung undicht ist? Was sind die Auswirkungen?
    • Wie können Sie einen Speicherverlust verhindern?
    • Wenn in Ihrer Anwendung ein Speicherverlust auftritt, verschwindet sie, wenn der Prozess beendet wird oder ist getötet? Oder wirken sich Speicherverluste in Ihrer Anwendung auch nach Abschluss des Prozesses auf andere Prozesse im System aus?
    • Und was ist mit nicht verwaltetem Code, auf den über COM Interop und / oder P / Invoke zugegriffen wird?
    08 June 2018
    ZoeAlain
14 answers
  • Die beste Erklärung, die ich gesehen habe, finden Sie in Kapitel 7 des kostenlosen Grundlagen der E-Book-Programmierung .

    Grundsätzlich tritt in .NET ein Speicherverlust auf, wenn Objekte referenziert werden sind verwurzelt und können daher nicht mit Müll gesammelt werden. Dies geschieht versehentlich, wenn Sie sich auf Verweise außerhalb des beabsichtigten Bereichs halten.

    Sie werden wissen, dass Sie Lecks haben, wenn Sie OutOfMemoryExceptions erhalten, oder dass Ihre Speichernutzung über das von Ihnen angegebene Maß hinausgeht. d erwarten ( PerfMon hat schöne Speicherindikatoren).

    Das Speichermodell von .NET ist das beste Mittel, um dies zu vermeiden. Insbesondere verstehe ich, wie der Müllsammler arbeitet und wie Referenzen arbeiten - ich verweise Sie erneut auf Kapitel 7 des E-Books. Achten Sie auch auf häufige Fallstricke, die wahrscheinlich die häufigsten sind. Wenn das Objekt A für ein Ereignis in Objekt B registriert ist, bleibt das Objekt A so lange in der Nähe, bis das Objekt B verschwindet weil B einen Verweis auf A enthält. Die Lösung besteht darin, die Registrierung Ihrer Ereignisse aufzuheben, wenn Sie fertig sind.

    Natürlich können Sie mit einem guten Speicherprofil Ihre Objektdiagramme sehen und die Verschachtelung / Referenzierung Ihrer Objekte untersuchen, um zu sehen, woher die Referenzen kommen und welches Stammobjekt dafür verantwortlich ist ( red-gate-Ameisenprofil , JetBrains dotMemory, memprofiler sind wirklich eine gute Wahl, oder Sie können die Nur-Text-Version WinDbg und SOS , aber ich würde ein kommerzielles / visuelles Produkt nur empfehlen, wenn Sie ein echter Guru sind.

    Ich glaube, dass nicht verwalteter Code seinen typischen Speicherverlusten unterliegt, mit Ausnahme der Freigabe Re

    14 May 2018
    q-l-pnlucaroni
  • Genau genommen verbraucht ein Speicherverlust Speicher, der vom Programm "nicht mehr verwendet" wird.

    "Nicht mehr verwendet" hat mehr als eine Bedeutung. es könnte bedeuten, dass kein Verweis mehr darauf besteht, dh völlig nicht wiederherstellbar ist, oder es kann referenziert, wiederherstellbar, nicht verwendet werden, aber das Programm behält die Verweise trotzdem bei. Nur das spätere gilt für .Net für perfekt verwaltete Objekte . Nicht alle Klassen sind jedoch perfekt, und zu einem bestimmten Zeitpunkt kann eine zugrunde liegende nicht verwaltete Implementierung Ressourcen für diesen Prozess dauerhaft verlieren.

    In allen Fällen verbraucht die Anwendung mehr Speicher als unbedingt erforderlich. Abhängig von der Menge, die durchgesickert wurde, können die Nebeneffekte von keiner über eine übermäßige Sammlung verursachte Verlangsamung, eine Reihe von Speicherausnahmen und schließlich einen schwerwiegenden Fehler mit nachfolgender erzwungener Prozessbeendigung erreichen.

    Sie wissen, dass bei einer Anwendung ein Speicherproblem vorliegt, wenn durch die Überwachung angezeigt wird, dass Ihrem Prozess nach jedem Speicherbereinigungszyklus immer mehr Speicher zugewiesen wird. In einem solchen Fall bleiben Sie entweder zu viel im Speicher oder eine zugrunde liegende nicht verwaltete Implementierung ist undicht.

    Bei den meisten Lecks werden die Ressourcen wiederhergestellt, wenn der Prozess beendet wird, jedoch einige Ressourcen werden in bestimmten Fällen nicht immer wiederhergestellt. GDI-Cursor-Handles sind dafür notorisch. Wenn Sie über einen prozessübergreifenden Kommunikationsmechanismus verfügen, wird der im anderen Prozess zugewiesene Speicher erst dann freigegeben, wenn dieser Prozess ihn freigibt oder beendet.

    01 August 2008
    Coincoin
  • Ich denke, die Fragen "Was ist ein Speicherleck" und "Was sind die Auswirkungen", wurden bereits gut beantwortet, aber ich wollte noch ein paar Dinge zu den anderen Fragen hinzufügen ...

    So können Sie verstehen, ob Ihre Anwendung undicht ist

    Eine interessante Möglichkeit ist das Öffnen von perfmon und fügen Sie Spuren für # Bytes in allen Heaps und # Gen 2 Collections hinzu, wobei Sie jeweils nur Ihren Prozess betrachten. Wenn durch das Ausüben eines bestimmten Features die Gesamtanzahl der Bytes erhöht wird und der Speicher nach der nächsten Gen-2-Sammlung erhalten bleibt, könnten Sie sagen, dass das Feature Speicher verliert.

    Wie

    Andere gute Meinungen wurden abgegeben. Ich würde nur hinzufügen, dass die am häufigsten übersehene Ursache von .NET-Speicherverlusten darin besteht, Ereignishandlern zu Objekten hinzuzufügen, ohne sie zu entfernen. Ein mit einem Objekt verknüpfter Ereignishandler ist eine Art Verweis auf dieses Objekt. Er verhindert daher auch die Erfassung, nachdem alle anderen Verweise gelöscht wurden. Denken Sie immer daran, Ereignishandler zu trennen (verwenden Sie die Syntax -= in C #).

    Verschwindet das Leck, wenn der Prozess abgeschlossen ist, und wie sieht es mit COM-Interop aus? < / strong>

    Wenn Ihr Prozess beendet wird, wird der gesamte seinem Adressraum zugeordnete Speicher vom Betriebssystem zurückgefordert, einschließlich aller COM-Objekte, die von DLLs bereitgestellt werden. COM-Objekte können vergleichsweise selten von separaten Prozessen bedient werden. Wenn Ihr Prozess beendet wird, sind Sie in diesem Fall möglicherweise noch für den Speicher verantwortlich, der in allen von Ihnen verwendeten COM-Server-Prozessen zugewiesen wird.

    26 January 2012
    Brian MainsSimon
  • Ich würde Speicherverluste als ein Objekt definieren, das nicht den gesamten zugewiesenen Speicher freigibt, nachdem es abgeschlossen wurde. Ich habe festgestellt, dass dies in Ihrer Anwendung passieren kann, wenn Sie Windows API und COM verwenden (d. H. Nicht verwalteter Code, der einen Fehler enthält oder nicht ordnungsgemäß verwaltet wird), im Framework und in Komponenten von Drittanbietern. Ich habe auch festgestellt, dass es nach dem Gebrauch bestimmter Objekte wie Stifte nicht zu spät kommt.

    Ich persönlich habe Out of Memory-Ausnahmen erlitten, die verursacht werden können, aber nicht ausschließlich Speicherlecks sind in Punktnetzanwendungen. (OOM kann auch vom Pinning stammen, siehe Pinning Artical ) . Wenn Sie keine OOM-Fehler erhalten oder überprüfen müssen, ob es sich um einen Speicherverlust handelt, besteht die einzige Möglichkeit darin, Ihre Anwendung zu profilieren.

    Ich würde auch Folgendes versuchen :

    a) Alles, was Idisposable implementiert, wird entweder mit einem finally-Block entsorgt oder die using-Anweisung enthält Pinsel, Stifte usw. (einige Leute argumentieren, alles zusätzlich auf Null zu setzen).

    b) Alles, was über eine close-Methode verfügt, wird mit using oder der using-Anweisung wieder geschlossen (obwohl using gefunden hat, dass das Objekt nicht immer geschlossen wird, je nachdem, ob Sie das Objekt außerhalb der using-Anweisung deklariert haben )

    c) Wenn Sie nicht verwalteten Code / Windows-APIs verwenden, werden diese anschließend korrekt behandelt. (Einige verfügen über bereinigte Methoden zum Freigeben von Ressourcen.)

    Ich hoffe, das hilft.

    01 August 2008
    Johnjulienpar
  • Wenn Sie ein Speicherverlust in .NET diagnostizieren müssen, überprüfen Sie diese Links:

    http://msdn.microsoft.com/de-de/magazine/cc163833.aspx

    http://msdn.microsoft.com/de-de/magazine/cc164138.aspx

    Diese Artikel beschreiben wie Sie einen Speicherauszug Ihres Prozesses erstellen und wie dieser analysiert wird, damit Sie zunächst feststellen können, ob Ihr Leck nicht verwaltet oder verwaltet wird und ob es verwaltet wird, wie es herauszufinden ist, woher es kommt.

    Microsoft hat auch ein neueres Tool, das beim Erstellen von Crash-Dumps hilft, um ADPlus zu ersetzen, und heißt DebugDiag.

    http://www.microsoft.com/do wnloads / details.aspx? FamilyID = 28bd5941 - c458 - 46f1 - b24d - f60151d875a3 & amp; displaylang = de

    19 January 2016
    vardAbdulla Abu Zakham
  • Die beste Erklärung für die Funktionsweise des Speicherbereinigers finden Sie in Jeff Richters CLR über C # buchen, (Kap. 20). Wenn Sie dies lesen, können Sie verstehen, wie Objekte bestehen bleiben.

    Eine der häufigsten Ursachen für versehentliches Verwurzeln von Objekten besteht darin, Ereignisse außerhalb einer Klasse anzuhängen. Wenn Sie ein externes Ereignis anschließen

    zB

     SomeExternalClass.Changed += new EventHandler(HandleIt);
     

    und vergessen Sie nicht, den Haken aufzuheben, wenn Sie ihn entsorgen, dann hat SomeExternalClass einen Ref zu Ihrer Klasse.

    Wie oben erwähnt, ist das SciTech memory profiler zeigt die Wurzeln von Objekten, von denen Sie annehmen, dass sie undicht sind.

    Es gibt jedoch auch eine sehr schnelle Möglichkeit, einen bestimmten Typ zu überprüfen, indem Sie einfach WnDBG verwenden (Sie können dies sogar im VS.NET-Direktfenster verwenden, wenn es angeschlossen ist):

     .loadby sos mscorwks
    !dumpheap -stat -type <TypeName>
     

    Nun tun Sie etwas, von dem Sie glauben, dass es Objekte dieses Typs zur Verfügung stellt (z. B. ein Fenster schließen). Es ist praktisch, hier einen Debug-Button zu haben, der System.GC.Collect() ein paar Mal ausgeführt wird.

    Dann führen Sie !dumpheap -stat -type <TypeName> erneut aus. Wenn die Nummer nicht gesunken ist oder nicht so viel wie erwartet, haben Sie eine Grundlage für weitere Untersuchungen. (Ich habe diesen Tipp von einem Seminar erhalten, das von Ingo Rammer ).

    19 January 2016
    vardAbdulla Abu Zakham
  • Ich schätze, in einer verwalteten Umgebung wäre es ein Leck, wenn Sie einen unnötigen Verweis auf einen großen Speicherplatz aufrechterhalten

    01 August 2008
    Bernard
  • Warum glauben die Leute, dass ein Speicherverlust in .NET nicht das gleiche wie ein anderes ist?

    Ein Speicherverlust ist, wenn Sie eine Verbindung zu einer Ressource herstellen und Lass es nicht gehen. Sie können dies sowohl in verwalteter als auch in nicht verwalteter Codierung tun.

    In Bezug auf .NET und andere Programmierwerkzeuge gibt es Ideen zur Speicherbereinigung und andere Möglichkeiten, um dies zu minimieren Machen Sie Ihre Anwendung zum Lecken. Die beste Methode zum Verhindern von Speicherverlusten ist jedoch, dass Sie das zugrunde liegende Speichermodell und die Funktionsweise der verwendeten Plattform auf der von Ihnen verwendeten Plattform verstehen müssen.

    < Wenn Sie glauben, dass GC und andere Magie Ihr Chaos bereinigen, ist dies der kurze Weg zu Speicherlecks und wird später schwer zu finden sein Zum Bereinigen wissen Sie, dass die Ressourcen, die Sie in Anspruch nehmen, in Ihrer Verantwortung liegen werden, und nicht die des Hausmeisters.

    In .NET dagegen eine Menge Die Leute denken, dass der GC alles aufräumt. Gut tut es etwas für Sie, aber Sie müssen sicherstellen, dass es so ist. .NET packt viele Dinge ein, sodass Sie nicht immer wissen, ob Sie mit einer verwalteten oder nicht verwalteten Ressource zu tun haben, und Sie müssen sich vergewissern, mit was Sie es zu tun haben. In der Regel müssen Sie auf Schriftarten, GDI-Ressourcen, Active Directory, Datenbanken usw. achten.

    In verwalteten Begriffen werde ich meinen Hals auf Die Zeile, die besagt, dass sie wegfällt, sobald der Prozess beendet / entfernt wird.

    Ich sehe, dass viele Leute dies haben, und ich hoffe wirklich, dass dies enden wird. Sie können den Benutzer nicht auffordern, Ihre App zu beenden, um Ihr Chaos zu bereinigen! Schauen Sie sich einen Browser an, der IE, FF usw. sein kann, und öffnen Sie beispielsweise Google Reader, lassen Sie ihn einige Tage stehen und schauen Sie nach bei was passiert

    Wenn Sie eine andere Registerkarte im Browser öffnen, zu einer Website navigieren und dann die Registerkarte schließen, die die andere Seite gehostet hat, durch die der Browser durchgesickert ist, glauben Sie, dass der Browser freigegeben wird die Erinnerung? Nein

    06 May 2017
    Nathan Tuggymitchdav
  • Ich werde mich mit Bernard darin einig sein, wie in .net ein Mem-Leck aussehen würde.

    Sie können ein Profil Ihrer Anwendung erstellen, um zu sehen, wie viel Speicher sie verbrauchen, und dies festzustellen Wenn es eine Menge Speicher verwaltet, wenn es nicht sein sollte, könnten Sie sagen, es hat ein Leck Sobald der Prozess beendet / entfernt wurde.

    Nicht verwalteter Code ist sein eigenes Tier, und wenn ein Leck darin vorhanden ist, folgt er einem Standard-Mem. Leckdefinition.

    01 December 2015
    SiyualSridhar Gonda
  • Ich denke, in einer verwalteten Umgebung wäre ein Leck ein unnötiger Hinweis auf einen großen Teil des Speichers.

    Absolut. Wenn Sie die .Dispose () -Methode nicht für Einwegobjekte verwenden, kann dies zu Undichtigkeiten führen. Am einfachsten geht dies mit einem using-Block, da er am Ende automatisch .Dispose () ausführt:

     StreamReader sr;
    using(sr = new StreamReader("somefile.txt"))
    {
        //do some stuff
    }
     

    Wenn Sie eine Klasse erstellen, die nicht verwaltete Objekte verwendet, und wenn Sie IDisposable nicht ordnungsgemäß implementieren, kann dies zu Speicherverlusten für die Benutzer Ihrer Klasse führen.

    06 August 2008
    Seibar