Produktionsdebugging für .NET...

37
Produktionsdebugging für .NET Framework-Anwendungen Debuggen von Speicherproblemen Zusammenfassung: Dieses Kapitel beschreibt die Herangehensweise beim Debuggen von Speicherbelegungsproblemen, die sich eventuell bei der Verwendung von ASP.NET-Anwendungen für den Benutzer ergeben. Zunächst wird die Speicherverwaltung in .NET, insbesondere die Rückforderung von nicht verwendetem Speicher durch den Garbage Collector (GC), erläutert. Anschließend führt Sie eine Schritt-für-Schritt- Anleitung durch das Debuggen eines Speicherbelegungsszenarios. Obwohl die Wiedergabe dieses Problems auf Ihrem Computer Ihnen u.U. aufgrund der verschiedenen Betriebssysteme und Laufzeitversionen nicht dieselben Ergebnisse liefert, sollten Sie eine ähnliche Ausgabe erhalten. Die Debuggingkonzepte sind dieselben. Da alle .NET Framework- Anwendungen dieselbe Speicherarchitektur verwenden, können Sie zudem Ihre hier gewonnenen Kenntnisse über die Speicherverwaltung in ASP.NET auf andere .NET-Umgebungen wie z.B. Konsolenanwendungen, Anwendungen des Betriebssystems Microsoft® Windows® und Windows- Dienste anwenden. Inhalt .NET-Speicherverwaltung und Garbage Collection Szenario: Speicherbelegung Schlussfolgerung .NET-Speicherverwaltung und Garbage Collection C- und C++-Programme waren von jeher anfällig für Arbeitsspeicherverluste, da die Entwickler die Speicherkapazitäten manuell zuordnen und freigeben mussten. In Microsoft® .NET entfällt dies, da .NET nicht verwendeten Speicher mit der Garbage Collection automatisch zurückfordert. Dadurch kann der Speicher sicherer und effizienter genutzt werden. Der Garbage Collector (GC) verfolgt mittels Referenzen Objekte, die Speicherblöcke belegen. Wenn ein Objekt auf Null gesetzt wird oder nicht mehr gültig ist, kennzeichnet es der GC als zurückforderbar. Er kann dem

Transcript of Produktionsdebugging für .NET...

Page 1: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Produktionsdebugging für .NET Framework-Anwendungen Debuggen von Speicherproblemen

Zusammenfassung: Dieses Kapitel beschreibt die Herangehensweise beim Debuggen von Speicherbelegungsproblemen, die sich eventuell bei der Verwendung von ASP.NET-Anwendungen für den Benutzer ergeben. Zunächst wird die Speicherverwaltung in .NET, insbesondere die Rückforderung von nicht verwendetem Speicher durch den Garbage Collector (GC), erläutert. Anschließend führt Sie eine Schritt-für-Schritt-Anleitung durch das Debuggen eines Speicherbelegungsszenarios.

Obwohl die Wiedergabe dieses Problems auf Ihrem Computer Ihnen u.U. aufgrund der verschiedenen Betriebssysteme und Laufzeitversionen nicht dieselben Ergebnisse liefert, sollten Sie eine ähnliche Ausgabe erhalten. Die Debuggingkonzepte sind dieselben. Da alle .NET Framework-Anwendungen dieselbe Speicherarchitektur verwenden, können Sie zudem Ihre hier gewonnenen Kenntnisse über die Speicherverwaltung in ASP.NET auf andere .NET-Umgebungen wie z.B. Konsolenanwendungen, Anwendungen des Betriebssystems Microsoft® Windows® und Windows-Dienste anwenden.

Inhalt

.NET-Speicherverwaltung und Garbage Collection

Szenario: Speicherbelegung

Schlussfolgerung

.NET-Speicherverwaltung und Garbage Collection

C- und C++-Programme waren von jeher anfällig für Arbeitsspeicherverluste, da die Entwickler die Speicherkapazitäten manuell zuordnen und freigeben mussten. In Microsoft® .NET entfällt dies, da .NET nicht verwendeten Speicher mit der Garbage Collection automatisch zurückfordert. Dadurch kann der Speicher sicherer und effizienter genutzt werden.

Der Garbage Collector (GC) verfolgt mittels Referenzen Objekte, die Speicherblöcke belegen. Wenn ein Objekt auf Null gesetzt wird oder nicht mehr gültig ist, kennzeichnet es der GC als zurückforderbar. Er kann dem

Page 2: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Betriebssystem Speicherblöcke, die von diesen zurückforderbaren Objekten referenziert werden, wieder zurückführen.

Der Vorteil eines GCs besteht darin, dass er die Objektauflistung verschiebt und eine große Anzahl von Objektauflistungen gleichzeitig ausführen kann. GCs verwenden oft mehr Speicher als die üblichen Speicherverwaltungsroutinen, wie z.B. Routinen, die von Windows-Betriebssystemen verwendet werden.

Der GC in .NET verwendet die Microsoft Win32®-API VirtualAlloc(), um einen Speicherblock für seinen Heap zu reservieren. Ein verwalteter .NET-Heap ist ein großer, zusammenhängender virtueller Speicherbereich. Der GC reserviert zunächst virtuellen Speicher und überträgt den Speicher dann bei Zunahme des verwalteten Heaps. Er verfolgt die nächste verfügbare Adresse am Ende des verwalteten Heaps und platziert an dieser Stelle die nächste Zuordnungsanforderung. Folglich werden alle verwalteten .NET-Speicherzuordnungen nacheinander im verwalteten Heap platziert. Dadurch wird die Zuordnungszeit enorm verkürzt, da der GC im Gegensatz zu regulären Verwaltungsprogrammen keine freie oder verknüpfte Liste mit Speicherblöcken nach einem freien Block in der geeigneten Größe durchsuchen muss. Mit der Zeit entstehen mit dem Löschen von Objekten Lücken im verwalteten Speicher. Bei der Garbage Collection komprimiert der GC den Heap und füllt die Lücken auf, indem er Zuordnungen mittels einer direkten Speicherkopie verschiebt. Abbildung 2.1 veranschaulicht dies.

Abbildung 2.1. Heapkomprimierung durch den Garbage Collector

Ausführliche Informationen zur .NET-Garbage Collection finden Sie in folgenden Referenzen:

• "Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework" von Jeffrey Richter, MSDN Magazine, November 2000 (http://msdn.microsoft.com/library/en-us/dnmag00/html/GCI.asp) (in Englisch).

• "Garbage Collection – Part 2: Automatic Memory Management in the Microsoft .NET Framework" von Jeffrey Richter, MSDN Magazine, Dezember 2000 (http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/GCI2.asp) (in Englisch).

Page 3: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

• Kapitel 19, "Automatic Memory Management (Garbage Collection)", in "Applied Microsoft .NET Framework Programming" von Jeffrey Richter (Microsoft Press, 2002) (in Englisch).

Generationen

Der GC verbessert die Speicherverwaltung, indem er Objekte in Generationen verschiedenen Alters aufteilt. Im Falle einer Auflistung werden Objekte in der jüngsten Generation aufgelistet. Wenn dadurch nicht genügend Speicher frei wird, können daraufhin auch ältere Generationen aufgelistet werden. Durch die Verwendung von Generationen muss der GC immer nur mit einer Teilmenge der zugeordneten Objekte arbeiten.

Der GC verwendet gegenwärtig drei Generationen: 0, 1 und 2. Zugeordnete Objekte gehören anfangs zur Generation 0. Auflistungen können eine Tiefe von 0, 1 oder 2 haben. Alle Objekte, die nach der Auflistung eine Tiefe von 0 haben, werden zu Generation 1 heraufgestuft. Objekte, die nach einer Auflistung eine Tiefe von 1 haben (Generation 0 und 1), werden nach Generation 2 verschoben. Abbildung 2.2 veranschaulicht die Migration zwischen Generationen.

Abbildung 2.2. Migration zwischen Generationen bei mehreren Auflistungen

Mit der Zeit werden die höheren Generationen mit den ältesten Objekten aufgefüllt. Diese höheren Generationen sollten stabiler sein und benötigen weniger Auflistungen. Aus diesem Grund befinden sich weniger Speicherkopien in höheren Generationen.

Die Auflistung einer bestimmten Generation erfolgt, wenn der Speichergrenzwert dieser Generation erreicht wird. In der Implementierung von .NET, Version 1.0, betragen die Anfangsgrenzwerte der Generationen 0, 1 und 2 jeweils 256 KB, 2 MB und 10 MB. Beachten Sie, dass der GC diese Grenzwerte auf Grundlage der Zuordnungsmuster einer Anwendung dynamisch anpassen kann. Objekte mit mehr als 85 KB werden automatisch im Large Object Heap platziert. Weitere Informationen hierzu finden Sie weiter hinten in diesem Kapitel.

Stämme

Mittels Objektreferenzen bestimmt der GC, ob ein bestimmter Speicherblock im verwalteten Heap aufgelistet werden kann oder nicht. Im Gegensatz zu anderen GC-Implementierungen haben die zugeordneten

Page 4: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Blöcke kein Heapflag, das anzeigt, ob der Block aufgelistet werden kann. Für jede Anwendung unterhält der GC eine Referenzverzeichnisstruktur, die die von der Anwendung referenzierten Objekte nachverfolgt. In Abbildung 2.3 ist diese Verzeichnisstruktur dargestellt.

Abbildung 2.3. Stammreferenz-Verzeichnisstruktur

Der GC behandelt ein Objekt als Stammobjekt, wenn es über mindestens ein übergeordnetes Objekt verfügt, das es referenziert. Jede Anwendung in .NET verfügt über mehrere Stämme, einschließlich globale und statische Objekte sowie die dazugehörigen Threadstapel und dynamisch instanziierte Objekte. Bevor er eine Garbage Collection durchführt, startet der GC beim Stammobjekt und arbeitet sich abwärts durch, um eine Verzeichnisstruktur mit allen Variablenreferenzen zu erstellen. Er erstellt eine Masterliste mit allen aktiven Objekten und durchsucht dann den verwalteten Heap nach Objekten, die nicht in dieser Liste aufgeführt sind.

Diese Art der Feststellung, ob ein Objekt aktiv ist oder nicht, mag im Vergleich zum Einsatz eines einfachen Flags in einem Speicherblockheader oder eines Referenzindikators kostspielig erscheinen. Sie gewährleistet jedoch eine durchgängige Genauigkeit. So könnte z.B. ein Objektreferenzindikator versehentlich über- oder unterreferenziert sein und ein Heapflag irrtümlich als gelöscht gesetzt werden, wenn der Speicherblock über aktive Referenzen verfügt. Der verwaltete Heap vermeidet diese Probleme, indem er vor der Auflistung alle aktiven Objekte aufzählt und eine Liste mit allen referenzierten Objekten erstellt. Zusätzlich werden mit dieser Methode auch Ringspeicherreferenzprobleme behandelt.

Verfügt ein Objekt über eine aktive Referenz, wird es als starkes Stammobjekt bezeichnet. .NET verwendet zudem das Konzept der Referenzen mit schwachen Stammobjekten. Eine schwache Referenz bietet Programmierern die Möglichkeit, dem GC anzuzeigen, dass sie auf ein Objekt zugreifen, aber die Auflistung des Objekts nicht verhindern

Page 5: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

möchten. Solch ein Objekt ist bis zur Auflistung durch den GC verfügbar. Wenn Sie z.B. ein großes Objekt zuordnen, könnten Sie es, anstatt es vollständig zu löschen und aufzulisten, zur möglichen Wiederverwendung aufbewahren, solange die Speicherkapazitäten keine Bereinigung des verwalteten Heaps erfordern. Folglich sind schwache Referenzen im Verhalten mit einem Cache zu vergleichen.

Large Object Heap

Der .NET-Speichermanager platziert alle Zuordnungen von mindestens 85.000 Byte in einem separaten Heap, dem sogenannten Large Object Heap. Dieser Heap besteht aus mehreren virtuellen Speicherblöcken, die nicht vom verwalteten Hauptheap abhängig sind. Ein separater Heap für größere Objekte ermöglicht eine effizientere Garbage Collection des verwalteten Hauptheaps, da zur Auflistung Speicher verschoben werden muss, was bei großen Speicherblocks recht kostenspielig ist. Berücksichtigen Sie jedoch bei der Zuordnung großer Speicher in .NET, dass der Large Object Heap nie komprimiert wird.

Wenn Sie z.B. einem einzelnen Block 1 MB an Speicher zuweisen, nimmt die Größe des Large Object Heaps um 1 MB zu. Wenn Sie dieses Objekt freigeben, gibt der Large Object Heap den virtuellen Speicher nicht frei und behält seine Größe von 1 MB. Wenn Sie später einen weiteren 500-KB-Block zuordnen, wird der neue Block im 1-MB-Speicherblock des Large Object Heaps zugeordnet. Während der Prozessdauer nimmt der Large Object Heap immer zu, um alle gegenwärtig referenzierten Zuordnungen von großen Blöcken aufzunehmen. Er nimmt jedoch bei der Freigabe von Objekten niemals ab, selbst im Falle einer Garbage Collection nicht. Abbildung 2.4 zeigt ein Beispiel für einen Large Object Heap.

Abbildung 2.4. Large Object Heap

Szenario: Speicherbelegung

Nachdem Sie nun erste Einblicke in die .NET-Speicherverwaltung und Garbage Collection gewonnen haben, lernen Sie im Anschluss, wie diese in ASP.NET-Anwendungen eingesetzt werden. In diesem Szenario wird erläutert, wie Speicherbelegungsprobleme gedebuggt werden. Wie Sie vielleicht bereits wissen, werden Speicherverluste durch die Freigabe von Speicherplatz verursacht, der dynamisch zugeordnet wurde. Ein geringer Speicherverlust wird wahrscheinlich nicht bemerkt und verursacht nur minimalen Schaden. Große Speicherverluste hingegen können die Leistung

Page 6: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

drastisch beeinträchtigen, da verfügbarer Speicher verloren geht. Zudem können andere Speicherprobleme auftreten, bei denen es sich zwar nicht um "echte" Speicherverluste handelt, die jedoch die entsprechenden Anzeichen zeigen. Dieses Szenario geht umfassend auf die letztgenannten Speicherprobleme ein.

Es folgen einige typische Kundenszenarios, bei denen Speicherprobleme vorliegen könnten:

• Szenario 1: Produkte werden über eine E-Commerce-Website verkauft. Browserclients beklagen den Verlust von Daten sowie Fehler vom Typ "Server Application Unavailable" (Serveranwendung nicht verfügbar). Sie müssen sich erneut anmelden und wissen nicht, warum. Zudem verlangsamt sich die Serverleistung bei zunehmender Speichernutzung.

• Szenario 2: Auf eine Website können Videodateien geladen werden. Wenn ein Browserclient eine große Datei lädt, wird der Vorgang recycelt und der Dateiupload abgebrochen.

Die Gedankengänge im Einzelnen

Beim Debuggen von Speicherproblemen sind viele Dinge zu prüfen. Abbildung 2.5 zeigt ein Flussdiagramm, das Sie bei der Behebung von Speicherbelegungsproblemen befolgen können.

Abbildung 2.5. Flussdiagramm zur Behebung von Speicherbelegungsproblemen

Page 7: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Auch wenn die einzelnen Gedankengänge in der folgenden Schritt-für-Schritt-Anleitung beschrieben werden, sollten wir vorab schon einmal einen detaillierteren Blick auf das Flussdiagramm werfen.

Weisen die Fehler auf Speicherverlustsymptome hin?

Wenn Sie mit Microsoft Internet Information Services (IIS) 5.x arbeiten, überprüfen Sie, ob das Anwendungsereignisprotokoll darauf hinweist, dass ein ASP-Vorgang recycelt wurde. Ist dies der Fall, wird eine ähnliche Fehlermeldung wie die Folgende angezeigt: "aspnet_wp.exe (PID: 1234) was recycled because memory consumption exceeded n MB (n percent of available RAM)" ("aspnet_wp.exe (PID: 1234) wurde recycelt, da mehr als n MB (n Prozent des verfügbaren RAM) Speicher belegt wurde").

Wo ist mein Speicher?

Als Nächstes wird festgestellt, welcher Prozess zu viel Speicher belegt. Tools wie der Systemmonitor oder der Task-Manager können solche Prozesse isolieren. Nachdem Sie festgestellt haben, welcher Prozess zu viel Speicher belegt, können Sie AutoDump+ (ADPlus) ausführen, um ein vollständiges Speicherabbild des Aspnet_wp.exe-Prozesses zu erstellen. Anschließend untersuchen Sie mit Hilfe des Debuggers WinDbg und der Debuggererweiterung SOS.dll die Differenz zwischen verwaltetem und systemeigenen Speicher. Dies wird später in diesem Kapitel behandelt.

Wenn das Projekt in einer kontrollierten Umgebung ausgeführt wird (z.B. während der Entwicklung, Qualitätssicherung (QA) oder beim Testen), reproduzieren Sie das Problem und führen ADPlus im -hang-Modus aus, um ein vollständiges Speicherabbild des Aspnet_wp.exe-Prozesses zu erstellen. Um die Dauer bis zum Prozessrecycling zu verlängern, können Sie den Standardgrenzwert von 60 Prozent mit dem memorylimit-Attribut im <processModel>-Element in machine.config erhöhen.

Sie können auch mit .NET-APIs bzw. dem Systemmonitor weitere Informationen erfassen. Mit dem Systemmonitor beispielsweise können Sie nach Mustern suchen, die entweder auf einen Verlust des verwalteten .NET-Speichers oder auf einen systemeigenen Speicherverlust hinweisen.

Belegung von systemeigenem Speicher

Wenn der Indikator Private Bytes im Systemmonitor ansteigt und der .NET-Indikator # of Bytes in all Heaps (Anzahl der Bytes in allen Heaps) unverändert bleibt, wird systemeigener Speicher belegt. Diese Indikatoren werden später in diesem Kapitel unter "Schritt-für-Schritt-Anleitung durch die Speicherbelegung" ausführlich behandelt.

Belegung von verwaltetem Speicher

Page 8: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Wenn Sie den Systemmonitor verwenden und der Indikator Private Bytes sowie der .NET-Indikator # of Bytes in all Heaps (Anzahl der Bytes in allen Heaps) identisch ansteigen, wird verwalteter Speicher belegt. Prüfen Sie die Größe des zugeordneten verwalteten Speichers, und beachten Sie das Vorgehen des GCs. Verwenden Sie in der Speicherabbilddatei SOS-Befehle, um die Größe des verwalteten Heaps aufzulisten, und vergleichen Sie sie mit der Gesamtgröße der Speicherabbilddatei. Überlegen Sie, welche Einzelheiten Sie über den Large Object Heap und die Generationen erfahren können. Stellen Sie fest, ob große Objekte (mind. 85 KB) oder kleinere Objekte den meisten Speicher belegen. Sind es große Objekte, schauen Sie sich die Detailinformationen zum Large Object Heap an. Sind es kleinere Objekte, überlegen Sie, welchen Inhalt die Generationen 0, 1 und 2 haben. Stellen Sie bei großen Objekten fest, ob sie einen Stamm haben bzw. (k)einen Stamm haben sollten. Besitzen sie keinen Stamm, sind sie Kandidaten für Auflistungen. Stellen Sie fest, ob sie abschließend ordnungsgemäß aufgelistet wurden.

Mit WinDbg und SOS.dll kann sich die Anzeige aller Detailinformationen zu einer Vielzahl kleiner Objekte schwieriger gestalten. In diesen Fällen ist es einfacher, mit dem Allocation Profiler nach Detailinformationen zu großen und kleinen Objekten zu suchen. In der Schritt-für-Schritt-Anleitung durch die Speicherbelegung werden alle hier genannten Tools zur Diagnose eines Speicherbelegungsproblems verwendet.

Schritt-für-Schritt-Anleitung durch die Speicherbelegung

Die nachfolgende schrittweise Anleitung stellt ein vereinfachtes, realistisches Szenario dar: Eine ASP.NET-Anwendung ordnet zu viel Speicher zu und führt schließlich Recyclings durch, da sie den im Prozessmodell zulässigen Speichergrenzwert überschreitet. Mit dieser Anleitung sollen die Techniken gezeigt werden, mit denen Sie ein derartiges Problem beheben können. Produktionsumgebungsszenarios sind u.U. nicht so eindeutig wie dieses vereinfachte Beispiel, aber Sie können ähnliche Techniken anwenden, um die Ursache für die Speicherbelegung herauszufinden.

Diese Schritt-für-Schritt-Anleitung behandelt einen großen Speicherverlust, der die Leistung drastisch beeinträchtigen kann, da verfügbarer Speicher verloren geht. Eine ASP.NET-Beispielseite ordnet große Objekte (je 20 MB) zu und speichert sie anschließend im ASP.NET-Cache zwischen. Standardmäßig wird der ASP.NET-Prozess recycelt, wenn mehr als 60 Prozent des verfügbaren RAM belegt werden. Diese Anleitung hilft Ihnen, den Prozess zu ermitteln, der zu viel Speicher belegt, sowie die Gründe dafür herauszufinden.

In diesem Szenario führen Sie die folgenden Schritte durch:

Page 9: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

1. Rufen Sie unter http://localhost/debugging/memory.aspx die ASP.NET-Seite auf, und prüfen Sie die in der Prozessmodelltabelle angezeigten Werte.

2. Folgen Sie den Überlegungen im Flussdiagramm, und suchen Sie die Fehler, die sowohl im Browser als auch im Anwendungsereignisprotokoll angezeigt werden.

3. Erstellen Sie eine Speicherabbilddatei, und untersuchen Sie die Abbilddaten mit Hilfe von WinDbg und SOS.dll.

4. Untersuchen Sie den verwalteten Speicher hinsichtlich des ASP.NET-Workerprozesses, und stellen Sie fest, welche Objekte am meisten Speicher belegen.

5. Überprüfen Sie den Quellcode, nachdem Sie in den Speicherauszügen Hinweise auf mögliche Problembereiche gefunden haben.

Basisansicht

Sammeln Sie mithilfe der Schritt-für-Schritt-Anleitung zunächst einige grundlegende Daten, um die Belegung von systemeigenem und verwaltetem Speicher zu vergleichen. Anweisungen zum Herunterladen der Beispielseiten finden Sie in Kapitel 1, "Einführung in Produktionsdebugging für .NET Framework-Anwendungen".

So zeigen Sie "Memory.aspx" an

• Öffnen Sie ein Browserfenster, und rufen Sie die Site http://localhost/Debugging/memory.aspx auf.

Notieren Sie sich die dort angezeigten Informationen, insbesondere die Felder und Werte in der Tabelle.

Die folgende Browseransicht dient als Grundlage für den Vergleich von Daten, nachdem Sie speicherbelegende Objekte erstellt haben.

Page 10: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Abbildung 2.6. Grundlegende Browserdaten

Die nachfolgende Tabelle enthält Erklärungen zur Anzeige dieser Felder:

Tabelle 2.1: Beschreibung der Felder in "Memory.aspx"

Feld Beschreibung StartTime Zeitpunkt, zu dem dieser Aspnet_wp.exe-Prozess

gestartet wurde. Age Dauer der Prozessausführung. ProcessID Dem Prozess zugewiesene ID. RequestCount Anzahl der ausgeführten Anforderungen,

ursprünglich Null. Status Aktueller Prozessstatus: Bei Alive wird der Prozess

ausgeführt, bei Shutting Down wurde mit dem Herunterfahren des Prozesses begonnen, bei ShutDown wurde der Prozess regulär nach Empfang einer entsprechenden Nachricht vom IIS-Prozess heruntergefahren, bei Terminated wurde der Prozess zwangsweise vom IIS-Prozess beendet.

ShutdownReason Ursache für das Herunterfahren eines Prozesses:

Page 11: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Bei Unexpected wurde der Prozess unerwartet heruntergefahren, bei Requests Limit überschritten vom Prozess ausgeführte Anforderungen den zulässigen Grenzwert, bei Request Queue Limit überschritten dem Prozess zugewiesene Anforderungen die in der Warteschlange zulässige Anzahl, bei Timeout wurde der Prozess neu gestartet, da er länger als erlaubt aktiv war, bei Idle Timeout überschritt der Prozess die zulässige Leerlaufzeit, bei Memory Limit Exceeded überschritt der Prozess den Speichergrenzwert pro Prozess.

PeakMemoryUsed Vom Prozess belegte maximale Speichermenge. Dieser Wert richtet sich nach dem Indikator Private Bytes (maximum amount) (Private Bytes, maximale Menge) im Systemmonitor.

Sie können den Code überprüfen und sich die Kommentare durchlesen, indem Sie eine weitere Instanz von Memory.aspx.cs in Microsoft Visual Studio® .NET oder im Editor öffnen.

Mit jedem Klick auf die Schaltfläche Allocate 20 MB Objects werden fünf eindeutige Cacheschlüssel und fünf 20-MB-Objekte im System.Web-Cache erstellt und gespeichert. Wenn Sie auf die Schaltfläche Allocate 200 K Objects klicken, werden 200-KB-Objekte im System.Web-Cache erstellt. Der Code hinter dieser Schaltfläche simuliert einen nicht schwerwiegenden Speicherverlust und ermöglicht das Experimentieren mit alternativen Testszenarios.

Free Memory ruft eine Liste mit Cacheschlüsseln aus dem Session-Bereich ab und löscht den Cache. Zudem ruft dieser Befehl die System.GC.Collect()-Methode für eine erzwungene Garbage Collection auf.

Anmerkung System.GC.Collect() dient zu Demonstrationszwecken und ist keine empfohlene Vorgehensweise. Durch explizites Aufrufen von GC.Collect() werden die automatischen Tuningfunktionen des GCs geändert. Durch wiederholtes Aufrufen von GC.Collect() werden alle Threads bis zur Beendigung der Auflistung unterbrochen. Dies kann die Leistung stark beeinträchtigen.

Refresh Stats schließlich aktualisiert die Speicherstatistik.

Mit dem Task-Manager und dem Systemmonitor bestätigen oder erhalten Sie weitere Informationen zum ASP.NET-Prozess:

So verwenden Sie den Task-Manager

Page 12: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

1. Öffnen Sie den Task-Manager. 2. Klicken Sie auf der Registerkarte Processes (Prozesse) auf das

Menü View (Ansicht), Select Columns (Spalten auswählen), und aktivieren Sie dann das Kontrollkästchen Virtual Memory Size (Größe des virtuellen Speichers).

Dadurch wird den Standardspalten virtueller Speicher hinzugefügt.

Anmerkung Wenn Sie Windows 2000 Server über einen Terminal Server-Client verwenden, müssen Sie das Kontrollkästchen Show processes from all users (Prozesse aller Benutzer anzeigen) aktivieren.

Wie groß ist der virtuelle Speicher des Aspnet_wp.exe-Prozesses? In diesem Test beträgt der virtuelle Speicher von Aspnet_wp.exe 9.820 KB. Dieser Wert stellt eine angemessene Grundlage dar.

Tabelle 2.2: Basisdaten Task-Manager

Prozess Virtuelle Speichergröße Aspnet_wp.exe 9.820 KB

Starten Sie den Systemmonitor.

So starten Sie den Systemmonitor

1. Klicken Sie in der Systemsteuerung auf Administrative Tools (Verwaltung), und doppelklicken Sie anschließend auf Performance (Leistung).

2. Klicken Sie auf der Symbolleiste des Systemmonitors auf '+', und wählen Sie anschließend im Dialogfeld Add Counters (Leistungsindikatoren hinzufügen) aus der Dropdownliste Performance object (Leistungsobjekt) den Eintrag .NET CLR Memory (.NET CLR-Speicher).

3. Klicken Sie im Feld Select instances from list (Instanzen wählen) auf aspnet_wp.

4. Wählen Sie mit STRG+Mausklick die in Abbildung 2.7 gezeigten Einträge aus dem Listenfeld Counters (Leistungsindikatoren) aus, und klicken Sie anschließend auf Add (Hinzufügen).

Wiederholen Sie den Vorgang für die Leistungsobjekte ASP.NET Applications (ASP.NET-Anwendungen) und Process (Prozess), und klicken Sie, nachdem Sie die entsprechenden Instanzen und Indikatoren ausgewählt haben, auf Add (Hinzufügen).

5. Klicken Sie auf Close (Schließen) und anschließend auf der Symbolleiste auf die Schaltfläche View Report (Bericht anzeigen),

Page 13: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

um zur Textansicht zu wechseln. Eine Anzeige ähnlich der nachfolgend in Abbildung 2.7 dargestellten wird eingeblendet.

Abbildung 2.7. Grunddaten Systemmonitor

Achten Sie im Systemmonitorbericht besonders auf # Bytes in all Heaps (Anzahl der Bytes in den Heaps), Large Object Heap Size (Objektheapgröße) und Cache API Entries (Cache-API-Einträge).

• # Bytes in all Heaps (Anzahl der Bytes in den Heaps) zeigt die Summe der Indikatoren Gen 0 Heap Size (Heapgröße der Generation 0), Gen 1 Heap Size (Heapgröße der Generation 1), Gen 2 Heap Size (Heapgröße der Generation 2) und Large Object Heap Size (Objektheapgröße) an. Der Indikator # Bytes in all Heaps (Anzahl der Bytes in den Heaps) gibt die Bytes des aktuell den Garbage Collection-Heaps zugewiesenen Speichers wieder.

• Large Object Heap Size (Objektheapgröße) zeigt die aktuelle Größe (in Byte) des Large Object Heap an. Beachten Sie, dass dieser Indikator nicht bei jeder Auflistung, sondern am Ende einer Garbage Collection aktualisiert wird.

• Cache API Entries (Cache-API-Einträge) zeigt die Gesamtanzahl der Einträge im Anwendungscache an.

Die Grundwerte vor der Speicherzuordnung lauten:

Page 14: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

• Large Object Heap Size (Objektheapgröße): 22.608 Byte • # Bytes in all Heaps (Anzahl der Bytes in den Heaps):

2.589.252 • Cache API Entries (Cache-API-Einträge): 0

Anmerkung Weitere Informationen zu den .NET-Leistungsindikatoren des Systemmonitors finden Sie unter:

• "Allgemeine .NET Framework-Referenz: Speicherleistungsindikatoren" in der MSDN-Website unter http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/gngrfmemoryperformancecounters.asp.

• ".NET Framework-Entwicklerhandbuch: Leistungsindikatoren für ASP.NET" in der MSDN-Website unter http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconperformancecountersforaspnet.asp.

Erster Zuordnungsdurchlauf

Nachdem Sie nun die grundlegenden Statistiken für die Anwendungs- und Systemmonitorindikatoren festgelegt haben und der ASP.NET-Prozess ausgeführt wird, legen Sie die Größe an systemeigenem und verwaltetem Speicher fest, der belegt wird. Klicken Sie auf der Seite Memory.aspx ein Mal auf Allocate 20 MB Objects. Ihre Browserdaten sollten in etwa denen in den nachfolgenden Tabellen ähneln:

Tabelle 2.3: Grundlegende Browserdaten und Browserdaten bei einer Zuordnung

Feld Grundwert Neuer Wert StartTime 07/08/2002 12:14:06

PM 07/08/2002 12:40:59 PM

Age 00:00:04.2961776 00:00:33:9585520 ProcessID 3.212 3.212 RequestCount 0 1 Status Alive Alive ShutdownReason N/A N/A PeakMemory Used 5.948 8.904

Aktualisierter Speicherstatus

Grundwert Neuer Wert

GC.TotalMemory 780 KB 100.912 KB Private Bytes 8.896 KB 117.616 KB

Auf der Seite wird eine neue Tabelle mit zwei Einträgen angezeigt:

Page 15: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

• GC.TotalMemory ist die Gesamtgröße an verwaltetem Speicher, die der GC-Heap verwalteten Objekten zugeordnet hat. (Diese Größe richtet sich nach dem Systemmonitorindikator # Bytes in all Heaps (Anzahl der Bytes in allen Heaps) für das .NET CLR Memory Performance-Objekt (.NET CLR-Speicherleistung).)

• Private Bytes ist die Gesamtmenge an systemeigenem Speicher, die ein Prozess zugewiesen hat, der nicht gemeinsam mit anderen Prozessen verwendet werden kann.

Wenn Sie auf Allocate 20 MB Objects klicken, erhöht sich der Wert im Feld RequestCount um 1, um die bis dahin abgeschlossenen Anforderungen anzuzeigen. Sie sehen ebenfalls, dass GC.TotalMemory und Private Bytes ca. 100 MB betragen.

Suchen Sie im Code der ASP.NET-Seite nach der Quelle der 100 MB:

Der Private Bytes-Wert beinhaltet die verwalteten und systemeigenen Zuordnungen für den Prozess.

Das Beispielszenario zeigt die Statistiken der Private Bytes- und GC.TotalMemory-Speicher direkt auf der ASP.NET-Seite an. Beim Produktionsdebuggen benötigen Sie u.U. andere Tools, wie z.B. den Task-Manager und den Systemmonitor, um diese Informationen zu erhalten. Mit dem Task-Manager können Sie systemeigene Daten anzeigen, mit dem Systemmonitor die Daten für verwalteten und systemeigenen Speicher.

Suchen Sie auf der Registerkarte Processes (Prozesse) im Task-Manager den Prozess Aspnet_wp.exe, der dieselbe Prozess-ID (PID) besitzt. Wie Sie sehen, ist die Größe des virtuellen Speichers auf nahezu 115.000 KB angestiegen.

Tabelle 2.4: Grunddaten sowie Daten bei einer Zuordnung im Task-Manager

Prozess Grundwert Neuer Wert Aspnet_wp.exe 9.820 KB 114.840 KB

Die Größe des virtuellen Speichers ist um ca. 100.000 KB angestiegen. Der ASP.NET-Prozess belegt fast den gesamten Speicher des Computers.

Anmerkung Die Spalte VM Size (Virtueller Speicher) im Task-Manager richtet sich annähernd nach dem Process: Private Bytes-Indikator des Systemmonitors.

In der Diagrammansicht des Systemmonitors sehen Sie, dass die Werte der Indikatoren Private Bytes und # Bytes in all Heaps (Anzahl der Bytes in den Heaps) um denselben Wert ansteigen. Dies deutet auf einen

Page 16: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Anstieg in der Belegung des verwalteten Speichers, nicht des systemeigenen Speichers, hin.

Abbildung 2.8 zeigt, wie die Speicherbelegung durch Klicken auf die Schaltfläche ansteigt. Sie ändern den Höchstwert der y-Koordinate in einer Kurve, indem Sie mit der rechten Maustaste auf die Kurve klicken und Properties (Eigenschaften) auswählen. Klicken Sie auf die Registerkarte Graph (Grafik), und ändern Sie den Wert im Feld Vertical scale Maximum (Vertikale Skalierung/Maximum).

Abbildung 2.8. Kurve im Systemmonitor

Zweiter Zuordnungsdurchlauf

Beim zweiten Schritt wird mehr Speicher belegt. Klicken Sie ein zweites Mal auf Allocate 20 MB Objects. Beachten Sie, wie sich die Werte auf der ASP.NET-Seite ändern, insbesondere RequestCount, PeakMemoryUsed und GC.TotalMemory.

Tabelle 2.5: Grundlegende Browserdaten sowie Browserdaten bei einer und zwei Zuordnungen

Page 17: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Feld Grundwert Eine Zuordnung Zwei Zuordnungen

StartTime 07/08/2002 12:14:06 PM

07/08/2002 12:40:59 PM

07/08/2002 13:25:51 PM

Age 00:00:04.2961776

00:00:23:9585520

00:47:33.1343328

ProcessID 3.212 3.212 3.212 RequestCount 0 1 2 Status Alive Alive Alive ShutdownReason

N/A N/A N/A

PeakMemory Used

5.948 8.904 113.752

Speicherstatus Grundwert Eine Zuordnung Zwei Zuordnungen

GC.TotalMemory 780 KB 100.912 KB 200.916 KB Private Bytes 8.896 KB 117.616 KB 221.450 KB

Die Auswirkungen dieses zweiten Vorgangs auf den Systemspeicher können Sie den Einzeldaten für den Prozess im Task-Manager entnehmen.

Tabelle 2.6: Grunddaten sowie Daten bei einer und zwei Zuordnungen im Task-Manager

Prozess Grundwert Eine Zuordnung Zwei Zuordnungen

Aspnet_wp.exe 9.820 KB 114.840 KB 216.240 KB

Der VM Size-Wert (Virtueller Speicher) hat sich um weitere 100.000 KB erhöht, und der Prozess Aspnet_wp.exe belegt weiterhin fast den gesamten Speicher.

Der Systemmonitorbericht und die Diagramme bestätigen diese Werte. Betrachten Sie nun den Indikator Cache API Entries (Cache-API-Einträge). Wie Sie im Code gesehen haben, führt jeder Mausklick eine Schleife aus, bei der fünf Cacheelemente erstellt werden. Da die Schleife zwei Mal ausgeführt wurde, liegen zehn Cache-API-Einträge vor.

Der Unterschied zwischen den Indikatoren #Bytes in all Heaps (Anzahl der Bytes in den Heaps) und Large Object Heap Size (Objektheapgröße) weist darauf hin, dass der Großteil des verwalteten Speichers vom Large Object Heap belegt wird. In Abbildung 2.9. wird dies dargestellt.

Page 18: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Abbildung 2.9. Daten Systemmonitor

Dritter Zuordnungsdurchlauf

Beim letzten Schritt wird noch mehr Speicher belegt. Klicken Sie ein drittes Mal auf Allocate 20 MB Objects, wechseln im Task-Manager zur Registerkarte Performance (Systemleistung) und überprüfen den Page File Usage History (Verlauf der Auslagerungsdateiauslastung).

Anmerkung Unter Windows XP zeigt der Task-Manager auf der Registerkarte Performance (Systemleistung) die Page File Usage (Auslagerungsdateiverwendung) an. Unter Windows 2000 hingegen zeigt er auf der Registerkarte Performance (Systemleistung) die Memory Usage (Speichernutzung) an.

Mit jedem Klick auf die Schaltfläche Allocate 20 MB Objects zeigt die Kurve einen starken Anstieg an, der sich nivelliert, bis erneut auf die Schaltfläche geklickt wird. Wird der Prozess recycelt, ist ein plötzlicher Abfall in der Page File Usage (Auslagerungsdateinutzung) sichtbar. Abbildung 2.10 zeigt diese Vorgänge im Task-Manager.

Page 19: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Abbildung 2.10. Daten Task-Manager

Mit dem Task-Manager können Sie die Gesamtleistung des Systems annähernd einschätzen. Reservierter Arbeitsspeicher wird dem Betriebssystem sowie Programmen zugeordnet, und unter Page File Usage History (Auslagerungsdateiauslastung) werden diese Werte in einer Kurve dargestellt. Bei jedem Mausklick steigt der Commit Charge-Wert (Zugesicherter Speicher) proportional zur Kurve.

Des Weiteren sind auch die Ergebnisse des recycelten Aspnet_wp.exe-Prozesses sichtbar. Wie erwähnt, nimmt die Speicherbelegung mit jedem Klick auf die Schaltfläche zu und wird erst beim Recyceln des Prozesses wieder freigegeben. Im Anwendungsereignisprotokoll können Sie überprüfen, ob der Prozess recycelt wurde.

Wechseln Sie im Browser zur ASP.NET-Seite, und klicken Sie auf die Schaltfläche Refresh Stats. Sie sehen jetzt eine zweite Tabelle mit den Daten für einen neuen Prozess. Da die Speichergrenze erreicht wurde, hat die Integritätsüberwachung des Prozessmodells den Originalprozess beendet und einen neuen Prozess gestartet. Vergleichen Sie die beiden Tabellen, und achten Sie dabei besonders auf die Felder Status und ShutdownReason und die Tabelle Updated Memory Stats.

Page 20: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Für den ersten Prozess änderte sich der Wert des Feldes Status von Alive zu Terminated, während der zweite Prozess nun den Status Alive hat. Der erste Prozess wurde beendet, da die Speichergrenze überschritten wurde. Beachten Sie, dass ASP.NET den Prozess beendet, nachdem Sie Speicher zugeordnet haben und die maximale Speichergrenze überschritten wurde.

Da der Prozess recycelt wurde, werden in der Tabelle Updated Memory Stats wieder die Grundwerte angezeigt.

Weitere Schritte

Refresh Stats aktualisiert lediglich die Statistik. Wenn Sie die Resultate variieren möchten, können Sie mit den Steuerelementen der Browseroberfläche experimentieren:

• Klicken Sie erneut auf Allocate 20 MB Objects anstatt auf Refresh Stats. Der RequestCount-Wert in der ersten Tabelle wird inkrementell erhöht, und in der zweiten Tabelle wird ein Anforderungsindikator von 0 angezeigt (ein neuer Workerprozess wurde erstellt). Das Prozessmodell verwendet intelligentes Routing, wenn die Speichergrenze erreicht ist. Es erkennt die Anforderung an, löscht den alten Prozess und erstellt einen neuen Prozess für die Anforderung.

• Klicken Sie ein weiteres Mal auf Allocate 20 MB Objects. Dadurch wird der RequestCount-Wert der zweiten Tabelle inkrementell erhöht, da wir es nun mit dem neuen Workerprozess zu tun haben und die Speichergrenze für diesen Prozess nicht erreicht wurde.

• Klicken Sie wiederholt auf Allocate 200 K Objects. Dadurch werden mehrere 200-KB-Objekte erstellt, die im Large Object Heap gesammelt werden. Sie sollten diese Option ausprobieren, da sie einen ähnlichen Codepfad mit weniger Speicherauslastung verwendet.

• Betrachten wir nun die bisherigen Schlussfolgerungen genauer: • Sie haben es mit der Auslastung von verwaltetem Speicher zu tun.

Das Systemmonitordiagramm zeigt, wie die Indikatoren Private Bytes und # Bytes in all Heaps (Anzahl der Bytes in den Heaps) identisch ansteigen.

• Der Aspnet_wp.exe-Prozess belegt fast den gesamten Speicher. Sobald er recycelt wird, normalisiert sich der Indikator für den reservierten Arbeitsspeicher.

• Der überwiegende Teil des verwalteten Heapspeichers befindet sich im Large Object Heap. Die Größe des Large Object Heaps entspricht nahezu dem Wert des Indikators Total # Bytes in all Heaps (Anzahl der Bytes in den Heaps).

Debuggen von Speicherauszugsdateien im Benutzermodus mittels WinDbg

Page 21: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Wenn Sie das Gelernte vertiefen und Näheres zu den Vorgängen im ASP.NET-Prozess erfahren möchten, erstellen Sie mithilfe von ADPlus eine Speicherabbilddatei, und untersuchen Sie sie mit WinDbg und SOS.dll. Weitere Informationen zu ADPlus finden Sie im Artikel Q286350, "SO WIRD'S GEMACHT: Verwenden von Autodump+ zur Problembehandlung bei "Hängen" und "Abstürzen"" in der Microsoft Knowledge Base unter http://support.microsoft.com/default.aspx?scid=kb;de;286350. Informationen zum Ausführen von ADPlus über einen Terminalserver finden Sie in Artikel Q323478, "PRB: You Cannot Debug Through a Terminal Server Session" in der Microsoft Knowledge Base unter http://support.microsoft.com/default.aspx?scid=kb;en-us;Q323478 (in Englisch).

Vorgehensweise

• Öffnen Sie ein Eingabeaufforderungsfenster, und geben Sie iisreset ein, um IIS neu zu starten.

Standardmäßig wird ein Aspnet_wp.exe-Prozess recycelt, wenn mehr als 60 Prozent des verfügbaren RAM belegt sind. Die Dauer bis zur Erreichung der Speichergrenze sollte kurz sein und nur wenig Zeit zum Debuggen lassen. Sie verhindern, dass der Prozess vor dem Debuggen beendet wird, indem Sie in der Registrierung das Standardverhalten von ASP.NET beim Recyceln eines Prozesses ändern.

Hinzufügen von Registrierungsschlüsseln

Sie müssen zwei Registrierungswerte hinzufügen: DebugOnHighMem und UnderDebugger. Anhand dieser Registrierungsschlüssel ruft ASP.NET DebugBreak auf, anstatt den Prozess zu beenden.

Anmerkung: Für die folgende Übung müssen Sie die Registrierung ändern. Dazu sollten Sie sie vorher immer erst sichern. Außerdem sollten Sie nach dem Debuggen die im Folgenden erstellten DWORDs löschen. Diese Registrierungs-DWORDs sind nicht dokumentiert und sollten nur während spezieller Debugsitzungen verwendet werden.

So erstellen Sie die Registrierungswerte

1. Starten Sie den Befehl Regedit, und suchen Sie den folgenden Schlüssel: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET.

2. Klicken Sie mit der rechten Maustaste auf ASP.NET, und wählen Sie New (Neu) und anschließend DWORD Value (DWORD-Wert) aus.

3. Ändern Sie den Namen des neuen Eintrags von New Value #1 (Neuer Wert #1) in DebugOnHighMem.

4. Doppelklicken Sie auf den neuen Namen, und ändern Sie den Hexadezimaldatenwert von 0 in 1.

Page 22: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

5. Erstellen Sie einen weiteren New DWORD Value (Neuen DWORD-Wert) mit dem Namen UnderDebugger. Belassen Sie die Datenwerte auf HEX 0.

Sie sollten nun ähnliche Einstellungen wie die in Abbildung 2.11 gezeigten erhalten.

Abbildung 2.11. Registry Editor (Registrierungs-Editor)

Die Überwachung der Speichergrenze wird automatisch deaktiviert, sobald einem Aspnet_wp.exe-Prozess ein Debugger hinzugefügt wird. Wird jedoch der Wert des UnderDebugger-DWORD-Wertes auf Null gesetzt, wird die Überwachung nicht deaktiviert.

Konfigurieren von ADPlus und Erstellen einer Speicherabbilddatei

ADPlus kann so konfiguriert werden, dass Sie bei Drücken der Tasten STRG+C im -crash-Modus ein volles Speicherabbild erstellen. Öffnen Sie die Skriptdatei ADPlus.vbs, und ändern Sie den Wert für Full_Dump_on_CONTRL_C von FALSE in TRUE. Der entsprechende Code aus ADPlus.vbs lautet:

Obwohl der Prozess nicht abstürzt, können Sie ADPlus zum Erfassen von Prozessdaten im -crash-Modus verwenden. Starten Sie zur Informationserfassung die ASP.NET-Seiten erneut.

So führen Sie ADPlus im "-crash"-Modus aus

1. Wechseln Sie zu http://localhost/debugging/memory.aspx. 2. Öffnen Sie eine Befehlseingabe, und starten Sie ADPlus aus der

Befehlszeile. 3. Geben Sie den -crash-Schalter und den Prozessnamen an (in

diesem Fall Aspnet_wp.exe).

Zudem können Sie wie im folgenden Beispiel zusätzliche Programminformationen mit der -quiet-Option unterdrücken:

In diesem Fall wird die ADPlus-Ausgabe in einem eindeutig benannten Unterverzeichnis von C:\debuggers gespeichert. Geben Sie bei der

Page 23: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Angabe des Ausgabeverzeichnisses den Pfad mit dem -o-Schalter an (siehe folgendes Beispiel):

Anmerkung Der -quiet-Schalter gewährleistet, dass Sie auch dann eine Speicherabbilddatei erstellen können, wenn kein Symbolpfad für ADPlus angegeben ist.

Die Debuggerausgabe ähnelt der Folgenden:

Zudem sollte ein minimiertes Fenster sichtbar sein, in dem CDB.exe ausgeführt wird.

Zu diesem Zeitpunkt erstellen Sie nun eine Speicherabbilddatei, um festzustellen, welcher Prozess Speicher belegt.

Anmerkung Die von ADPlus generierten Speicherabbilddateien können extrem groß sein. Mit jedem Klicken auf die Schaltfläche Allocate 20 MB Objects werden 100 MB zugeordnet. Überlegen Sie daher, wieviel freier Festplattenspeicher auf Ihrem Computer zur Verfügung steht. Wenn Sie 512 MB RAM haben und drei Mal auf die Schaltfläche klicken, müssen mindestens 300 MB an Festplattenspeicher verfügbar sein.

Sie erstellen eine Speicherabbilddatei, indem Sie mit der ASP.NET-Seite Objekte erstellen, die Speicher belegen.

So ordnen Sie Speicher zu

1. Wechseln Sie im Browser zur Seite Memory.aspx. 2. Klicken Sie drei Mal auf Allocate 20 MB Objects. Die

Speichergrenze ist nach dem dritten Klick erreicht, und CDB.exe erstellt nun ein Speicherabbild.

3. Klicken Sie auf Refresh Stats.

Der Debugger beendet den Prozess, erstellt eine Protokolldatei und wird beendet. Suchen Sie die von ADPlus generierten Dateien. Wenn Sie keinen Pfad in der ADPlus-Befehlszeile angegeben haben, werden diese Dateien in einem Verzeichnis gespeichert, dessen Name sich aus dem Datum und der Uhrzeit des Absturzes zusammensetzt (siehe folgendes Beispiel):

Nachfolgend werden die Dateien beschrieben, die normalerweise von ADPlus generiert werden:

• Autodump+-report.txt ist ein von ADPlus.vbs erstellter Bericht. Er enthält eine Liste mit den ADPlus bekannten Konstanten und deren aktuellen Einstellungen. Dieser Bericht dient zu Diagnosezwecken, wenn die Skriptdatei ADPlus.vbs nach Änderungen nicht mehr ordnungsgemäß funktioniert.

Page 24: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

• PID-1234__process.exe.cfg wird an CDB.exe übergeben, um die auszuführenden Befehle in einem Skript zu erfassen. Diese Datei kann zur Problemdiagnose beim Ausführen von ADPlus.vbs hilfreich sein.

• PID-1234__PROCESS.EXE__Reason__full/mini_timestamp.dmp ist die vollständige Speicherabbilddatei für den Prozess. Die Zahl nach der PID gibt die Prozess-ID für den abgebildeten Prozess an. Process.exe wird durch den Prozessnamen, mini_timestamp durch einen Zeitstempel und Reason durch eine Zeichenfolge ersetzt, die den Grund für die Abbilderstellung angibt (z.B. STRG+C für ein Absturzabbild). Ein typischer Name für eine Speicherabbilddatei könnte daher PID-344__ASPNET_WP.EXE__CTRL-C__full_2002-05-19_19-43-59-798_0158.dmp lauten. Diese Beispieldatei hat eine Größe von 358 MB.

• PID-1234__PROCESS.EXE__Reason__full/mini_timestamp.log ist ein Ausgabeprotokoll des Debuggers. Diese Datei kann nützlich sein, wenn Sie nach dem Verlauf von Ausnahmen oder Ereignissen suchen, die vor dem Fehler stattgefunden haben. Wiederum werden Teile des Dateinamens durch die PID, den Prozessnamen und den Grund ersetzt.

• Process_List.txt ist die Ausgabe von Tlist.exe -v. Mit dieser Datei bestimmt ADPlus.vbs die PIDs und Namen von Prozessen, die auf dem Computer ausgeführt werden.

Untersuchen der Speicherabbilddatei

Untersuchen Sie die Speicherabbilddatei, die beim Recyceln des Aspnet_wp.exe-Prozesses erstellt wurde.

So untersuchen Sie die Speicherabbilddatei mit WinDbg

1. Zeigen Sie im Menü Start auf Debugging Tools for Windows, und klicken Sie anschließend auf WinDbg.

2. Klicken Sie im Menü File auf Open Crash Dump. 3. Wählen Sie die entsprechende Speicherabbilddatei aus, und klicken

Sie auf Open. 4. Beantworten Sie ggf. die Eingabeaufforderung nach dem Speichern

der Basisarbeitsbereichinformationen mit No. 5. Wenn ein Disassemblyfenster geöffnet wird, schließen Sie es und

klicken im Menü Window auf Automatically Open Disassembly.

Für die Module, mit denen der Debugger die Speicherabbilddatei analysiert, müssen Symbolpfade eingegeben werden. Die für den Debuggingcomputer erforderlichen Symboldateiversionen müssen den Versionen auf dem System entsprechen, auf dem die Speicherabbilddatei

Page 25: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

erstellt wurde. Für dieses Szenario sind Symbole für das .NET Framework-SDK, Visual C Runtime und Windows erforderlich.

Führen Sie zur Eingabe der Symbolpfade einen der folgenden Schritte aus:

• Geben Sie in der Befehlszeile Folgendes ein: • Geben Sie den Symbolpfad für WinDbg über die

_NT_SYMBOL_PATH-Umgebungsvariable ein. • Klicken Sie in WinDbg im Menü File auf Symbol File Path und

geben anschließend Folgendes ein:

"SRV" im Pfad weist WinDbg an, Symbole vom externen Symbolserver in den lokalen Symbolcache zu kopieren.

So verwenden Sie dieselben Symbolpfade für andere Speicherabbilder

• Klicken Sie im Menü File auf Save Workspace As, und geben Sie anschließend einen Namen für die gespeicherten Pfade ein, z.B. .NET-Debuggingsymbole.

WinDbg debuggt systemeigenen Code. Zur Untersuchung von verwaltetem Code müssen Sie die Debuggererweiterung SOS.dll laden.

Anmerkung Installieren Sie die Debuggererweiterung SOS.dll, falls diese nicht bereits installiert ist. Downloadanweisungen finden Sie in Kapitel 1, "Einführung in Produktionsdebugging für .NET Framework-Anwendungen".

So untersuchen Sie verwalteten Code

1. Drücken Sie die Tasten ALT+1, um das WinDbg-Befehlsfenster zu öffnen.

2. Geben Sie .load <SOS>\SOS.dll ein, um die Erweiterung zu laden, und ersetzen Sie dann <SOS> durch den Speicherort von SOS.dll.

3. Mit dem Befehl !findtable initialisieren Sie SOS mit den Tabelleninformationen zur Laufzeitversion, die Sie debuggen.

Die Ausgabe sollte ähnlich der Folgenden aussehen:

Anmerkung SOS.dll benötigt eine der .NET-Laufzeitversion entsprechende BIN-Datei. Im vorigen Beispiel wurden zwei BIN-Dateien untersucht, ehe die richtige Version gefunden wurde. Zukünftige Versionen von SOS benötigen keine BIN-Datei.

Da Sie ADPlus zum Erstellen eines vollen Speicherabbildes konfiguriert haben und dieses Abbild mit einer Referenz auf STRG+C im Dateinamen generiert wurde, wissen Sie, dass DebugBreak aufgerufen wurde und die

Page 26: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Integritätsüberwachung des Prozessmodells eine übermäßige Speicherbelegung festgestellt hat.

ADPlus erstellte das Speicherabbild, als der Aspnet_wp.exe-Prozess recycelt wurde. Wie Sie im Eintrag des Anwendungsereignisprotokolls gesehen haben, überschritt die Speicherbelegung 60 Prozent des verfügbaren RAM. Zur Behebung dieses Speicherbelegungsproblems müssen Sie die Speicherabbilddatei untersuchen. Dieser Vorgang beinhaltet einige Schritte, die nicht immer intuitiv sind. Sie werden in den folgenden Abschnitten erläutert.

Analysieren des Speicherabbildes: Zusammenfassung

Zunächst folgt eine Zusammenfassung der Schritte, mit denen Sie die Speicherabbilddatei analysieren.

Bedenken Sie beim Umgang mit Speicherbelegungsproblemen die Vorgehensweise des GCs. Mit dem !eeheap-WinDbg-Befehl führen Sie die Größe des verwalteten Heaps auf und vergleichen sie anschließend mit der Gesamtgröße der Speicherabbilddatei.

Als Nächstes stellen Sie fest, welche verwalteten .NET-Objekte Speicher im verwalteten Heap belegen. In diesem Beispiel stellen Sie mit dem !dumpheap-Befehl fest, wie viele System.Byte []-Objekte sich im Large Object Heap befinden.

Sie müssen wissen, wie lange diese Objekte bestehen bleiben und wie groß sie sind. Der !gcroot-Befehl zeigt, dass die System.Byte []-Objekte eine starke Referenz haben, d.h., sie besitzen einen Stamm, da sie von der System.Web.Caching.Cache-Klasse referenziert werden.

Jetzt haben Sie also vom ASP.NET-Cache referenzierte Objekte gefunden. Stellen Sie nun fest, wieviel Speicher vom Cache referenziert wird.

Mit dem für die Assembly und den Klassennamen qualifizierten !name2ee-Befehl suchen Sie nach der Speicheradresse des System.Web.Caching.Cache. Dabei wird eine MethodTable-Adresse zurückgegeben, und Sie können mit dem !dumpheap-Befehl den Inhalt des verwalteten Heapspeichers für die Objekte mit dieser MethodTable-Adresse abbilden.

Der !dumpheap-Befehl liefert die eigentliche System.Web.Caching.Cache-Objektadresse, die dann zusammen mit dem !objsize-Befehl zur Suche nach der Anzahl der Bytes verwendet werden kann, die der Stamm im GC-Heap aktiv hält. Da diese Größe mit der Größe der Speicherabbilddatei vergleichbar ist, können Sie davon ausgehen, dass ein Großteil des verwalteten Speichers vom System.Web.Caching.Cache-Objekt referenziert wird.

Page 27: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Analysieren des Speicherabbildes: Ausführliche Informationen

Betrachten Sie zunächst die Größe des GC-Heaps, und vergleichen Sie sie dann mit der Gesamtgröße der Speicherabbilddatei.

Führen Sie mit dem !eeheap-Befehl die GC-Heapgröße und die Startadresse für Generation 0, 1, 2 sowie den Large Object Heap auf. Anschließend können Sie die GC-Heapgröße mit der Gesamtgröße der Speicherabbilddatei vergleichen.

Untersuchen Sie die GC-Heapgröße mit !eeheap -gc:

In diesem Fall beträgt die GC-Heapgröße über 300 MB, und das gesamte Speicherabbild hatte eine Größe von 358 MB. Mit dem !dumpheap -stat-Befehl stellen Sie fest, welche verwalteten .NET-Objekte Speicher im GC-Heap belegen. Die Ausgabe dieses Befehls teilt sich in die vier Spalten MT, Count, TotalSize und Class Name auf. Die MT-Ausgabe gibt die Methodentabelle wieder, die den Objekttyp bestimmt. Die MTs werden nach Größe in aufsteigender Reihenfolge aufgeführt. Unter TotalSize wird die Objektgröße, multipliziert mit der Anzahl der Objekte, aufgeführt.

Anmerkung Aufgrund der Datenmenge, die der !dumpheap–stat -Befehl sammeln und anzeigen muss, kann seine Ausführung eine geraume Zeit in Anspruch nehmen.

Der nachfolgende Codeauszug zeigt die ersten der 14.459 Objekte, die der !dumpheap–stat-Befehl aufgeführt hat.

Das Ende der dumpheap -stat-Liste befindet sich im zweiten nachfolgenden Codebeispiel. Die Objekte mit den größten TotalSize-Einträgen befinden sich am Ende der MT-Liste. Dazu gehören System.String, System.Byte [] und System.Object []:

System.String ist das letzte Objekt in der Liste, da es über die höchste Gesamtgröße (TotalSize) verfügt. Der Free-Eintrag stellt Objekte dar, die nicht referenziert sind und für die eine Garbage Collection ausgeführt wurde, deren Speicher jedoch nicht komprimiert und für das Betriebssystem freigegeben wurde.

Unmittelbar auf diese Daten folgt eine Liste der Objekte im Large Object Heap, die sämtliche Objekte mit mehr als 85 KB enthält.

Ausführliche Informationen zu Objekten im Large Object Heap erhalten Sie mithilfe des !gcroot-Befehls, der nach Objektstämmen sucht. Sie geben ein Objekt mittels seiner Adresse aus der dumpheap -stat-Ausgabe an. !gcroot 17b90018 z.B. liefert Informationen zum ersten System.Byte []-Objekt in der vorherigen Liste. Nachfolgend nun die Ausgabe von !gcroot:

Page 28: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Die Zeilen Scan Thread zeigen an, dass der !gcroot-Befehl Threads nach Stammreferenzen auf Objekte untersucht. Die Zeilen Scan HandleTable zeigen an, dass der Befehl auch die Handletabellen nach Stämmen durchsucht. Jede Anwendungsdomäne (oder AppDomain), also eine isolierte Umgebung, in der Anwendungen ausgeführt werden, besitzt eine Handletabelle, wobei es sich einfach um eine andere Quelle der Stammreferenzen handelt. Referenzen für einen Thread finden Sie in Registern, Argumenten oder lokalen Variablen.

Wenn die Ausgabe HANDLE(Strong) enthält, wurde eine starke Referenz gefunden, d.h., dieses Objekt besitzt einen Stamm, und es kann keine Garbage Collection ausgeführt werden. Weitere Referenztypen finden Sie im Anhang.

Das Speicherabbild zeigt ähnliche Daten für jedes System.Byte []-Objekt, das der !gcroot-Befehl gescannt hat. Versuchen Sie, eine andere Adresse aus der Ausgabe von dumpheap -stat an !gcroot zu übergeben. Die Ausgabe ist dieselbe wie beim vorherigen System.Byte []-Objekt, allerdings ist die Adresse für System.Web.Caching.CacheEntry gekennzeichnet. Die anderen Klassen kennzeichnen Auflistungen.

Es wäre hilfreich zu wissen, wieviel Speicher im Cache referenziert ist. Mithilfe des !name2ee-Befehls suchen Sie nach der Speicheradresse von System.Web.Caching.Cache. Dieser Befehl verwendet zwei Parameter – den Assemblynamen und den voll qualifizierten Klassennamen, System.Web.Caching.Cache. Wenn Sie den Assemblynamen nicht kennen, können Sie ihn in der .NET Framework-SDK-Dokumentation nachschlagen. Beachten Sie, dass Sie ähnliche Daten erhalten, wenn Sie System.Web.Caching.CacheSingle verwenden.

Anmerkung EEClass ist eine interne Struktur zur Darstellung einer .NET-Klasse. Weitere Informationen zur Ausgabe aus SOS-Befehlen finden Sie in der SOS-Hilfe.

Mit dem Befehl !dumpheap, der die MethodTable-Adresse weitergibt, erstellen Sie ein Abbild vom Inhalt des verwalteten Speichers für Objekte dieses Typs. Beispiel:

Nachfolgend finden Sie die von !dumpheap erwartete Ausgabe:

Die Verwendung des -mt-Schalters mag zunächst verwirrend wirken, da Sie keine spezifischen Informationen zu MethodTable benötigen. Wenn die Adresse eines Objekts jedoch an !dumpheap -mt weitergeleitet wird, werden alle ausgeführten Objekte dieses Typs in dieser Anwendungsdomäne aufgeführt. Bei mehreren Anwendungsdomänen wird jede Instanz des Objekts hier aufgeführt.

Mit diesen Informationen können Sie die Größe jedes Objekts abrufen, indem Sie die Adresse an den !objsize-Befehl weiterleiten. In diesem Fall

Page 29: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

ist nur eine Adresse vorhanden. Verwenden Sie daher zum Abbilden der Größe von System.Web.Caching.Cache den Befehl !objsize 0108b8ac. Nachfolgend finden Sie die von !objsize erwartete Ausgabe:

Anmerkung Führen Sie den !objsize-Befehl ohne Parameter aus, um alle Stämme im Prozess aufzulisten.

Weitere Informationen zum Caching in ASP.NET finden Sie unter "ASP.NET Performance Tips and Best Practices" auf der GotDotNet-Website unter http://www.gotdotnet.com/team/asp/ASP.NET Performance Tips and Tricks.aspx (in Englisch).

Freigeben von verwaltetem Speicher

Geben Sie den verwalteten Speicher frei, und bedenken Sie die Auswirkung auf den virtuellen Speicher.

So stellen Sie sicher, dass alles von Grund auf neu gestartet wird

1. Öffnen Sie ein Eingabeaufforderungsfenster, und geben Sie iisreset ein, um IIS neu zu starten.

2. Wechseln Sie zu http://localhost/debugging/memory.aspx. 3. Führen Sie den Systemmonitor aus, und stellen Sie sicher, dass

folgende Indikatoren gesetzt sind: Private Bytes und # Bytes in all Heaps (Anzahl der Bytes in den Heaps) für Aspnet_wp.exe.

4. Klicken Sie ein Mal auf Allocate 20 MB Objects. Sie sehen eine Ausgabe ähnlich der in Abbildung 2.8 gezeigten.

Beachten Sie die im Systemmonitor angezeigten Änderungen. Die Aspnet_wp.exe-Indikatoren Private Bytes und # Bytes in all Heaps (Anzahl der Bytes in den Heaps) erhöhen sich proportional.

5. Klicken Sie erneut auf Allocate 20 MB Objects, und beachten Sie die Änderungen im Systemmonitordiagramm.

Sobald Sie auf die Schaltfläche klicken, erhöhen sich die Indikatoren Private Bytes und #Bytes in All Heaps (Anzahl der Bytes in den Heaps) proportional.

Abbildung 2.12 zeigt die Ergebnisse im Systemmonitor nach zweimaligem Klicken auf Allocate 20 MB Objects. Wenn Sie zurück zum Browser wechseln und auf Free Memory klicken, sehen Sie, dass das Systemmonitorprotokoll selbst nach Klicken auf die Schaltfläche den Maximalwert für Private Bytes mit 222 MB angibt.

Page 30: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Abbildung 2.12. Systemmonitordaten nach Speicherzuordnung

Nachfolgend finden Sie einen Auszug aus dem Code hinter der Schaltfläche Free Memory:

Der Code enthält zudem einen Aufruf von GC.Collect(). Er löscht die Cacheobjekte und verursacht eine Garbage Collection, aber es wird kein durch den Large Object Heap zugeordneter virtueller Speicher freigegeben. Abbildung 2.13 zeigt, dass der Cache geleert wird und die GC.TotalMemory-Belegung abnimmt. Der Indikator Private Bytes bleibt jedoch weiterhin hoch.

Page 31: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC
Page 32: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Abbildung 2.13. Browserdaten nach Klicken auf "Free Memory"

Wenn Sie auf die Schaltfläche Free Memory klicken, wird der Speicher bis auf 1 MB freigegeben. Der Indikator # Bytes in all Heaps (Anzahl der Bytes in den Heaps) nimmt deutlich ab, jedoch bleibt der Indikator Private Bytes wegen des Large Object Heaps unverändert. In Abbildung 2.14. wird dies dargestellt.

Abbildung 2.14. Systemmonitorkurve nach Klicken auf "Free Memory"

Erfassen eines Speicherabbildes

Sie erhalten weitere Informationen zum Prozessstatus, indem Sie ADPlus im -hang-Modus ausführen, um ein Speicherabbild eines Prozessstatus zu erfassen:

Starten Sie WinDbg, laden Sie die Speicherabbilddatei, legen Sie den Symbolpfad fest, und laden und initialisieren Sie die SOS-Debuggererweiterung. Ermitteln Sie dann mit dem !eeheap -gc-Befehl die Größe des verwalteten Heaps.

Das Speicherabbild zeigt, dass die GC-Heapgröße 1 MB und nicht 222 MB beträgt. Dies bedeutet, dass der gesamte Speicher bis auf 1 MB

Page 33: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

aufgelistet wurde. Da die Größe der zugeordneten Objekte mehr als 20 MB betrug, können Sie davon ausgehen, dass alle Objekte aus dem Heap entfernt wurden. Der Private Bytes-Indikator für Aspnet_wp zeigt weiterhin 222 MB an; Sie müssen das Problem also näher untersuchen.

Verwenden Sie im Debugger den !dumpheap-Befehl mit dem "-stat"-Flag. Die Ausgabe ähnelt der Folgenden:

Zusammenfassend lässt sich festhalten, dass die ASP.NET-Seite große Objekte mit einer Größe von 20 MB zuordnet und sie anschließend im ASP.NET-Cache zwischenspeichert. Da die zugeordneten Objekte größer sind als 85 KB, werden sie im Large Object Heap zugeordnet. Wenn Objekte aus dem Cache entfernt werden, verringert sich der verwaltete Speicher (angezeigt durch den Systemmonitorindikator # Bytes in all Heaps (Anzahl der Bytes in den Heaps)) von 200 MB auf 1 MB. Die privaten Bytes für den Prozess nehmen jedoch nicht ab und betragen weiterhin ca. 222 MB. Obwohl verwalteter Speicher freigegeben wurde, bleibt die Speichermenge, die durch die VirtualAlloc-API zugeordnet wurde, dem Prozess zugeordnet.

Hierbei handelt es sich um eine bekannte Einschränkung des Large Object Heaps in Version 1.0. Er nimmt zu, um die Speichermenge aller Objekte aufzunehmen, die gleichzeitig aktiv sind. Wenn die Objekte freigegeben werden, wird der Speicher für neue große Speicherzuordnungen wiederverwendet. Die privaten Bytes nehmen jedoch bei Freigabe der Objekte ab. Dies wird in .NET Framework, Version 1.1, behoben sein.

Bis jetzt haben Sie in diesem Kapitel Folgendes gelernt:

• Wie kann verwalteter Code übermäßig Speicher belegen? • Wie und wann werden ASP.NET-Prozesse recycelt? • Techniken zum Debuggen von Speicherbelegungsproblemen • Verwenden von Tools wie Systemmonitor, Task-Manager, WinDbg

und SOS.dll während des Debuggens

Analysieren von Speicherverlusten mit dem Allocation Profiler

Der Allocation Profiler ist ein weiteres Tool, mit dem sich die Ursachen von Speicherbelegungsproblemen näher bestimmen lassen. Er untersucht den verwalteten Heap, wenn eine Anwendung ausgeführt wird, und stellt die Speicherzuordnung im Heap grafisch dar. In diesem Abschnitt zeigen Sie mit diesem Tool an, was passiert, wenn Objekte mit mehr als 85 KB im Large Object Heap zugeordnet werden. Der Allocation Profiler zeigt den Stamm der größten Objekte sowie die entsprechende Menge an zugeordnetem Speicher an.

Bevor Sie den Allocation Profiler im ASP.NET-Code verwenden, müssen Sie die Datei machine.config modifizieren und das username-Attribut im

Page 34: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

<processModel>-Element von machine in system ändern. Dadurch werden Berechtigungen zum Ausführen des Tools aktiviert. Wenn Sie die Arbeit mit dem Tool beendet haben, müssen Sie das username-Attribut wieder zurück in machine ändern, um keine Sicherheitsverletzungen beim Ausführen im Systemkonto zu riskieren.

So führen Sie Allocation Profiler aus

1. Führen Sie die Datei Allocationprofiler.exe in C:\Debuggers\AllocProf aus.

2. Wählen Sie im Menü File die Option Profile ASP.NET.

Daraufhin werden mehrere Befehlsfenster zu Informationszwecken angezeigt. Eines dieser Fenster zeigt an, dass das Tool den IIS Admin-Dienst stoppt, ein anderes, dass es den World Wide Web-Server startet. Der Titel des Allocation Profiler-Fensters wird in "Stopping IIS" geändert. IIS startet dann neu, und als Fenstertitel wird "Waiting for ASP.NET worker process to start up" angezeigt. Das Tool wartet also auf den Aufruf von Aspnet_wp.exe durch die erste ASP.NET-Seite.

3. Browsen Sie zu http://localhost/debugging/memory.aspx, um den ASP.NET-Workerprozess zu starten. Der Titel des Allocation Profiler-Fensters wird in "Profiling: ASP.NET" geändert.

4. Deaktivieren Sie das Kontrollkästchen Profiling active, und schließen Sie das Fenster Allocation Graph for: ASP.NET. Aktivieren Sie anschließend wieder das Kontrollkästchen Profiling active.

Der Allocation Profiler beginnt nun, die Zuordnungsstatistik für den Prozess zu sammeln.

5. Wechseln Sie zum Browserfenster, und klicken Sie zwei Mal auf Allocate 20 MB Objects.

6. Wechseln Sie zum Allocation Profiler, und deaktivieren Sie das Kontrollkästchen Profiling active.

7. Schieben Sie die horizontale Bildlaufleiste nach rechts, um durch die Zuordnungen zu blättern.

Abbildung 2.15. Zuordnungskurve

Page 35: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Der Bildschirm zeigt, dass der Button::OnClick-Handler die Memory::btn20MB_Click-Methode aufruft, die 191 MB an System.Byte-Arrayobjekten erstellt.

So zeigen Sie die Heapkurve an

1. Schließen Sie das Fenster Allocation Graph for: ASP.NET. Dies ist die Zuordnungskurve für ASP.NET.

2. Wechseln Sie zum Allocation Profiler-Fenster, und klicken Sie dann auf Show Heap Now. Daraufhin wird ein neues Allocation Profiler-Fenster namens "Heap Graph for ASP.NET" angezeigt.

3. Gehen Sie im Fenster mithilfe der Bildlaufleiste nach ganz rechts. Sie sehen dort die Zuordnung für das System.Byte []-Objekt.

Abbildung 2.16. Heapkurve

Das vorletzte Rechteck zeigt, dass das System.Byte []-Objekt seinen Stamm im System.Web-Cache hat. Dies wird durch die Referenzen in der Referenzverzeichnisstruktur von Caching.CacheSingle und Caching.CacheEntry angezeigt. Beachten Sie, dass Caching.CacheEntry aufgerufen wurde und eine Größe von 191 MB hat. Dies bedeutet, dass ein Großteil des Speichers vom Cache belegt ist.

So zeigen Sie das Histogramm an

1. Schließen Sie das Kurvenfenster. 2. Klicken Sie im Allocation Profiler-Fenster im Menü View auf

Histogram by Age.

Page 36: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Abbildung 2.17. Histogram by age (Histogramm nach Alter)

3. Gehen Sie mit der Bildlaufleiste links im Fenster Histogram by Age for Live Objects nach rechts, bis Sie einen dicken roten Balken sehen.

Die System.Byte []-Objekte stehen am Anfang der Liste mit dem Gesamtspeicher, der von Live-Objekten belegt wird.

4. Platzieren Sie den Mauspfeil auf dem roten Balken, um weitere Informationen zu erhalten.

5. Klicken Sie mit der rechten Maustaste auf den roten Balken, der System.Byte [] darstellt, und klicken Sie anschließend im Menü Context auf Show Who Allocated.

Die ursprüngliche Allocation Graph for ASP.NET (Zuordnungskurve für ASP.NET) wird angezeigt.

Allocation Profiler kann auch die Stammverzeichnisstruktur nachverfolgen, Aufrufer und Aufgerufene anzeigen sowie anzeigen, welcher Aufruf welchen Speicherblock zugeordnet hat.

So zeigen Sie Verzeichnisstrukturinformationen an

1. Klicken Sie im Fenster Allocation Graph for Object mit der rechten Maustaste auf die Leiste Memory: btn20MB_Click, und wählen Sie anschließend callers & callees. Dadurch wird die gesamte Aufrufverzeichnisstruktur markiert.

2. Klicken Sie mit der rechten Maustaste in den markierten Bereich, klicken Sie auf Copy as text to clipboard, und fügen Sie dann den Text in den Editor ein.

Folgende Informationen werden angezeigt:

Page 37: Produktionsdebugging für .NET Framework-Anwendungendownload.microsoft.com/download/9/2/3/923d72fb-0076-49b6... · 2018. 10. 16. · Bei der Garbage Collection komprimiert der GC

Diese Verzeichnisstruktur zeigt, wie der Aufruf von btn20MB_Click das große Objekt erstellt hat.

Wenn Sie Ihre Arbeit mit dem Allocation Profiler beendet haben, klicken Sie auf Kill ASP.NET. Ändern Sie das username-Attribut im <processModel>-Element in machine.config von system wieder zurück zu machine, um die Berechtigungen einzuschränken. Sie vermeiden dadurch Sicherheitsverletzungen, die durch das Ausführen unter system verursacht werden können.

Der Allocation Profiler hat den verwalteten Heap untersucht und gezeigt, dass das 20-MB-Objekt durch das btn20MB_Click-Ereignis erstellt wurde. Der eigentliche Code ruft von btn20MB_Click bis CreateLargeObject auf, wodurch System.Byte [] erstellt wird. Im Releasebuild ist CreateLargeObject aus Optimierungs- bzw. Inlinegründen nicht enthalten. Dies wird ausführlich in Kapitel 3, "Debuggen von Konfliktproblemen", erläutert. Ein Debugbuild würde den Aufruf von btn20MB_Click bis CreateLargeObject zeigen. Bei beiden Builds sehen Sie, dass das große Objekt einen Stamm besaß (und nicht vom GC aufgelistet werden konnte), und dass den großen Objekten eine beträchtliche Speichermenge zugeordnet wurde.

Schlussfolgerung

Dieses Kapitel behandelte folgende Themen:

• Verwenden von Microsoft-Tools zum Analysieren und Debuggen von Speicherzuordnungsproblemen

• Zuordnen von Objekten in verwalteten Heaps • Funktionsweise der .NET-Garbage Collection

Mit dem Task-Manager und dem Systemmonitor sammeln Sie nützliche Beweise zur Analyse von Speicherverlusten. Mit WinDbg und der SOS-Erweiterung können Sie aufzeigen, wo verwalteter Speicher in einer Anwendung zugeordnet wird. Mit dem Allocation Profiler zeigen Sie, wie verwalteter Speicher zugeordnet wurde. Außerdem wird er bei der Suche nach Objektstämmen verwendet.

Abschließend haben Sie gelernt, zuerst sorgfältig abzuwägen, bevor Sie Objekte mit einer Größe von mehr als 85 KB in ASP.NET-Anwendungen verwenden, da der Speicher im Large Object Heap von .NET Framework, Version 1.0, nicht vom GC zurückgefordert wird.

© 2003 Microsoft Corporation. Alle Rechte vorbehalten. Rechtliche Hinweise.