web-dev-qa-db-de.com

Welche Strategien und Tools sind hilfreich, um Speicherlecks in .NET zu finden?

Ich habe 10 Jahre lang C++ geschrieben. Ich habe Speicherprobleme festgestellt, die jedoch mit vertretbarem Aufwand behoben werden konnten.

In den letzten Jahren habe ich C # geschrieben. Ich habe immer noch viele Gedächtnisprobleme. Sie sind aufgrund der Unbestimmtheit schwer zu diagnostizieren und zu beheben, und weil die C # -Philosophie besagt, dass Sie sich über solche Dinge keine Sorgen machen sollten, wenn Sie dies auf jeden Fall tun.

Ein besonderes Problem ist, dass ich alles im Code explizit entsorgen und bereinigen muss. Wenn nicht, helfen die Speicherprofiler nicht wirklich, weil so viel Spreu um Sie herum schwebt, dass Sie in all den Daten, die sie Ihnen anzeigen möchten, kein Leck finden können. Ich frage mich, ob ich die falsche Idee habe oder ob das Tool, das ich habe, nicht das Beste ist.

Welche Strategien und Tools sind nützlich, um Speicherlecks in .NET zu beheben?

148
Scott Langham

Ich verwende Scitechs MemProfiler , wenn ich einen Speicherverlust vermute.

Bisher habe ich festgestellt, dass es sehr zuverlässig und leistungsstark ist. Es hat meinen Speck bei mindestens einer Gelegenheit gerettet.

Der GC funktioniert in .NET IMO sehr gut, aber genau wie bei jeder anderen Sprache oder Plattform kann es passieren, dass Sie schlechten Code schreiben.

51
GEOCHET

Versuchen Sie die in diesem Blog-Beitrag beschriebene Lösung . Hier ist die Essenz:

    public void Dispose ()
    {
        // Dispose logic here ...

        // It's a bad error if someone forgets to call Dispose,
        // so in Debug builds, we put a finalizer in to detect
        // the error. If Dispose is called, we suppress the
        // finalizer.
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

#if DEBUG
    ~TimedLock()
    {
        // If this finalizer runs, someone somewhere failed to
        // call Dispose, which means we've failed to leave
        // a monitor!
        System.Diagnostics.Debug.Fail("Undisposed lock");
    }
#endif
41
Jay Bazuzi

Wir haben Ants Profiler Pro von der Red Gate-Software in unserem Projekt verwendet. Es funktioniert sehr gut für alle .NET-basierten Anwendungen.

Wir haben festgestellt, dass der .NET Garbage Collector beim Bereinigen von In-Memory-Objekten (wie es sein sollte) sehr "sicher" ist. Es würde Objekte in der Nähe behalten, nur weil wir sie möglicherweise irgendwann in der Zukunft verwenden. Dies bedeutete, dass wir vorsichtiger mit der Anzahl der Objekte umgehen mussten, die wir im Speicher aufgeblasen hatten. Am Ende haben wir alle unsere Datenobjekte auf "Inflate-on-Demand" (kurz bevor ein Feld angefordert wird) umgestellt, um den Speicheraufwand zu verringern und die Leistung zu steigern.

EDIT: Hier ist eine weitere Erklärung, was ich mit "Inflate on Demand" meine. In unserem Objektmodell unserer Datenbank verwenden wir Eigenschaften eines übergeordneten Objekts, um die untergeordneten Objekte verfügbar zu machen. Wenn wir beispielsweise einen Datensatz hätten, der eins zu eins auf einen anderen "Detail" - oder "Nachschlage" -Datensatz verweist, würden wir ihn folgendermaßen strukturieren:

class ParentObject
   Private mRelatedObject as New CRelatedObject
   public Readonly property RelatedObject() as CRelatedObject
      get
         mRelatedObject.getWithID(RelatedObjectID)
         return mRelatedObject
      end get
   end property
End class

Wir haben festgestellt, dass das obige System einige echte Speicher- und Leistungsprobleme verursachte, wenn sich viele Datensätze im Speicher befanden. Deshalb haben wir auf ein System umgestellt, bei dem Objekte nur dann aufgeblasen wurden, wenn sie angefordert wurden, und Datenbankaufrufe nur dann durchgeführt wurden, wenn dies erforderlich war:

class ParentObject
   Private mRelatedObject as CRelatedObject
   Public ReadOnly Property RelatedObject() as CRelatedObject
      Get
         If mRelatedObject is Nothing
            mRelatedObject = New CRelatedObject
         End If
         If mRelatedObject.isEmptyObject
            mRelatedObject.getWithID(RelatedObjectID)
         End If
         return mRelatedObject
      end get
   end Property
end class

Dies erwies sich als wesentlich effizienter, da Objekte bis zu ihrer Verwendung nicht genügend Arbeitsspeicher hatten (auf die Methode Get wurde zugegriffen). Dies führte zu einer sehr starken Leistungssteigerung bei der Begrenzung der Datenbankzugriffe und einem enormen Speichergewinn.

17
Mark

Sie müssen sich noch um den Arbeitsspeicher kümmern, wenn Sie verwalteten Code schreiben, es sei denn, Ihre Anwendung ist trivial. Ich werde zwei Dinge vorschlagen: erstens lesen CLR über C # weil es Ihnen hilft, die Speicherverwaltung in .NET zu verstehen. Zweitens lernen Sie, ein Werkzeug wie CLRProfiler (Microsoft). Dies kann Ihnen eine Vorstellung davon geben, was Ihren Speicherverlust verursacht (z. B. können Sie sich die Fragmentierung Ihres großen Objekthaufens ansehen).

7
Zac Gochenour

Verwenden Sie nicht verwalteten Code? Wenn Sie laut Microsoft keinen nicht verwalteten Code verwenden, sind Speicherverluste im herkömmlichen Sinne nicht möglich.

Der von einer Anwendung verwendete Speicher wird möglicherweise jedoch nicht freigegeben, sodass die Speicherzuordnung einer Anwendung während der gesamten Lebensdauer der Anwendung zunehmen kann.

From Ermitteln von Speicherlecks in der Common Language Runtime bei Microsoft.com

In einer .NET Framework-Anwendung kann ein Speicherverlust auftreten, wenn Sie nicht verwalteten Code als Teil der Anwendung verwenden. Dieser nicht verwaltete Code kann zu Speicherverlusten führen, und die .NET Framework-Laufzeit kann dieses Problem nicht beheben.

Darüber hinaus scheint, ein Projekt nur über ein Speicherverlust zu verfügen. Diese Bedingung kann auftreten, wenn viele große Objekte (z. B. DataTable-Objekte) deklariert und dann einer Auflistung (z. B. einem DataSet) hinzugefügt werden. Die Ressourcen, die diese Objekte besitzen, werden möglicherweise nie freigegeben, und die Ressourcen bleiben für den gesamten Programmablauf erhalten. Dies scheint ein Leck zu sein, aber es ist eigentlich nur ein Symptom für die Art und Weise, wie Speicher im Programm zugewiesen wird.

Um diese Art von Problem zu lösen, können Sie IDisposable implementieren. Wenn Sie einige der Strategien für den Umgang mit Speicherverwaltung sehen möchten, würde ich vorschlagen, nach IDisposable, XNA, Speicherverwaltung zu suchen, wie es Spieleentwickler benötigen mehr vorhersehbare Müllabfuhr und so muss der GC sein Ding machen.

Ein häufiger Fehler besteht darin, keine Ereignishandler zu entfernen, die ein Objekt abonnieren. Ein Event-Handler-Abonnement verhindert, dass ein Objekt wiederverwendet wird. Schauen Sie sich auch die Anweisung sing an, mit der Sie einen begrenzten Bereich für die Lebensdauer einer Ressource erstellen können.

6

Dieser Blog hat einige wirklich wundervolle exemplarische Vorgehensweisen, die windbg und andere Tools verwenden, um Speicherlecks aller Art aufzuspüren. Ausgezeichnete Lektüre, um Ihre Fähigkeiten zu entwickeln.

5
twk

Ich hatte gerade einen Speicherverlust in einem Windows-Dienst, den ich behoben habe.

Zuerst habe ich versucht MemProfiler . Ich fand es sehr schwer zu bedienen und überhaupt nicht benutzerfreundlich.

Dann habe ich JustTrace verwendet, was einfacher zu verwenden ist und Ihnen mehr Details zu den Objekten gibt, die nicht richtig angeordnet sind.

Dadurch konnte ich das Speicherleck sehr einfach lösen.

5
billybob

Big Guns - Debugging Tools für Windows

Dies ist eine erstaunliche Sammlung von Werkzeugen. Sie können damit sowohl verwaltete als auch nicht verwaltete Heaps analysieren und dies auch offline tun. Dies war sehr praktisch, um eine unserer ASP.NET-Anwendungen zu debuggen, die aufgrund von Speicherüberlastung weiter recycelt wurden. Ich musste nur einen vollständigen Speicherauszug des auf dem Produktionsserver ausgeführten Lebensprozesses erstellen. Alle Analysen wurden offline in WinDbg durchgeführt. (Es stellte sich heraus, dass einige Entwickler den speicherinternen Sitzungsspeicher überbeanspruchten.)

"Wenn es kaputt ist ..." Blog hat sehr nützliche Artikel zu diesem Thema.

3
Constantin

Wenn die beobachteten Lecks auf eine außer Kontrolle geratene Cache-Implementierung zurückzuführen sind, ist dies ein Szenario, in dem Sie möglicherweise die Verwendung von WeakReference in Betracht ziehen möchten. Dies kann dazu beitragen, dass der Speicher bei Bedarf freigegeben wird.

Allerdings ist es meiner Meinung nach besser, eine maßgeschneiderte Lösung in Betracht zu ziehen - nur Sie wissen wirklich, wie lange Sie die Objekte aufbewahren müssen. Daher ist es in der Regel die beste Methode, den entsprechenden Housekeeping-Code für Ihre Situation zu entwerfen.

3
Chris Ballard

Das Beste, was Sie beachten sollten, ist, die Verweise auf Ihre Objekte im Auge zu behalten. Es ist sehr einfach, Verweise auf Objekte aufzuhängen, die Sie nicht mehr interessieren. Wenn Sie etwas nicht mehr verwenden, entfernen Sie es.

Gewöhnen Sie sich an die Verwendung eines Cache-Providers mit gleitendem Ablauf, sodass dereferenziert und bereinigt wird, wenn für ein gewünschtes Zeitfenster kein Verweis vorhanden ist. Wenn jedoch häufig darauf zugegriffen wird, wird dies im Speicher vermerkt.

2
Gord

Nach einem meiner Fixes für verwaltete Anwendungen hatte ich das gleiche Problem, z. B. wie ich überprüfe, ob meine Anwendung nach meiner nächsten Änderung nicht denselben Speicherverlust aufweist. Daher habe ich ein Framework wie Object Release Verification geschrieben. Schauen Sie sich das an das NuGet-Paket ObjectReleaseVerification . Ein Beispiel finden Sie hier https://github.com/outcoldman/OutcoldSolutions-ObjectReleaseVerification-Sample und Informationen zu diesem Beispiel http://outcoldman.ru/en/blog/ show/322

2
outcoldman

Eines der besten Tools ist die Verwendung von Debugging Tools for Windows und die Erstellung eines Speicherauszugs des Prozesses mit adplus Verwenden Sie windbg und das sos Plugin, um den Prozessspeicher, Threads, und call stacks.

Mit dieser Methode können Sie auch Probleme auf Servern identifizieren. Geben Sie nach der Installation der Tools das Verzeichnis frei, stellen Sie dann über (Net Use) eine Verbindung zur Freigabe vom Server her und führen Sie entweder einen Absturz durch oder hängen Sie den Prozess aus.

Dann offline analysieren.

2

Ich bevorzuge dotmemory von Jetbrains

2
josepainumkal

Ab Visual Studio 2015 sollten Sie ein sofort einsatzbereites Speicherbelegungs-Diagnosetool zum Sammeln und Analysieren von Speicher verwenden Nutzungsdaten.

Mit dem Speicherauslastungstool können Sie einen oder mehrere Snapshots des verwalteten und systemeigenen Speicherheaps erstellen, um die Auswirkungen der Objekttypen auf die Speichernutzung zu verstehen.

0