Übung 2: Nachverfolgen der Zuordnungen von Benutzermodusprozessen
Heap-Zuordnungen werden direkt über Heap-APIs (HeapAlloc, HeapRealloc und C/C++-Zuweisungen wie neue, alloc, Realloc, Calloc) durchgeführt und werden mit drei Arten von Heaps unterstützt:
Mainline NT Heap – Services-Zuweisungsanforderungen von Größen kleiner als 64 KB.
Niedriger Fragmentierungs-Heap – Bestehend aus Teilsegmenten, die Dienstzuweisungsanforderungen von festen Größenblöcken erfüllen.
VirtualAlloc – Dienstzuweisungsanforderungen von Größen größer als 64 KB.
VirtualAlloc wird für große dynamische Speicherzuweisungen verwendet, die direkt über die VirtualAlloc-API vorgenommen werden. Die typische Verwendung ist in der Regel für Bitmaps oder Puffer. Sie können VirtualAlloc verwenden, um einen Block von Seiten zu reservieren und dann zusätzliche Aufrufe an VirtualAlloc vorzunehmen, um einzelne Seiten aus dem reservierten Block zu binden. Dadurch kann ein Prozess einen Bereich des virtuellen Adressraums reservieren, ohne physischen Speicher zu verwenden, bis er benötigt wird.
In diesem Bereich gibt es zwei Konzepte:
Reservierter Arbeitsspeicher: Behält einen Adressbereich für die Verwendung vor, erhält jedoch keine Speicherressourcen.
Festgelegter Arbeitsspeicher: Stellt sicher, dass entweder physischer Arbeitsspeicher oder Seitendateispeicher verfügbar ist, wenn auf die Adressen verwiesen wird.
In dieser Übung erfahren Sie, wie Sie Ablaufverfolgungen sammeln, um zu untersuchen, wie ein Benutzermodusprozess Arbeitsspeicher zuordnet.
Die Übung konzentriert sich auf einen Dummy-Testprozess namens MemoryTestApp.exe , der Speicher durch ordnet:
Die VirtualAlloc-API zum Commit großer Speicherpuffer.
Der neue C++- Operator zum Instanziieren kleiner Objekte.
Sie können MemoryTestApp.exe hier herunterladen.
Schritt 1: Sammeln einer virtuellenAlloc/Heap-Ablaufverfolgung mithilfe von WPR
Große Speicherzuweisungen sind in der Regel die, die den Fußabdruck eines Prozesses beeinflussen und von der VirtualAlloc-API unterstützt werden. Hier sollten alle Untersuchungen beginnen, aber es ist auch möglich, dass ein Prozess mit kleineren Zuweisungen (z. B. Speicherlecks mit dem neuen Operator in C++usw.) falsch funktioniert. Heap-Ablaufverfolgung wird nützlich, wenn diese Situation geschieht.
Schritt 1.1: Vorbereiten des Systems für die Heap-Ablaufverfolgung
Die Heap-Ablaufverfolgung sollte optional und erledigt werden, wenn die VirtualAlloc-Analyse keine relevante Erklärung für ein Speichernutzungsproblem bereitstellt. Heap-Ablaufverfolgung führt zu größeren Spuren, und es wird empfohlen, die Ablaufverfolgung nur für die einzelnen Prozesse zu aktivieren, die Sie untersuchen.
Fügen Sie den Registrierungsschlüssel für den Vorgang des Interesses hinzu (MemoryTestApp.exe in diesem Fall); Die Heap-Ablaufverfolgung wird dann für jede nachfolgende Prozesserstellung aktiviert.
reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /t REG_DWORD /d 1 /f
Schritt 1.2: Erfassen einer Ablaufverfolgung mithilfe von WPR
In diesem Schritt sammeln Sie eine Ablaufverfolgung mithilfe von WPR , die VirtualAlloc - und Heap-Daten enthält.
Öffnen Sie WPR , und ändern Sie die Ablaufverfolgungskonfiguration.
Wählen Sie die Anbieter "VirtualAlloc " und "Heap " aus.
Wählen Sie General (Allgemein) als Leistungsszenario aus.
Wählen Sie allgemein als Protokollierungsmodus aus.
Klicken Sie auf "Start ", um die Ablaufverfolgung zu starten.
Starten Sie MemoryTestApp.exe, und warten Sie, bis der Vorgang beendet werden soll (es sollte etwa 30 Sekunden dauern).
Kehren Sie zu WPR zurück, speichern Sie die Ablaufverfolgung, und öffnen Sie sie mit Windows Leistungsanalyse (WPA).
Öffnen Sie das Menü Trace (Ablaufverfolgung), und wählen Sie Configure symbols path (Symbolpfad konfigurieren) aus.
- Geben Sie den Pfad des Symbolcaches an. Weitere Informationen zu Symbolen finden Sie auf der Seite Symbolunterstützung auf MSDN.
Öffnen Sie das Menü Ablaufverfolgung, und wählen Sie Load symbols (Symbole laden) aus.
Sie verfügen jetzt über eine Ablaufverfolgung, die alle Speicherzuweisungsmuster für den MemoryTestApp.exe Prozess während der Lebensdauer enthält.
Schritt 2: Überprüfen der dynamischen Zuordnungen von VirtualAlloc
Die detaillierten VirtualAlloc-Daten werden über das Diagramm "VirtualAlloc Commit Lifetimes" in WPA verfügbar gemacht. Andere interessante Spalten sind die folgenden:
Column | Beschreibung |
---|---|
Prozess | Der Name des Prozesses, der Speicherzuweisungen über VirtualAlloc ausführt. |
Commit-Stapel | Der Aufrufstapel, der den Codepfad anzeigt, der zum zugewiesenen Speicher führt. |
Commit Time | Der Zeitstempel, an dem Speicher zugewiesen wurde. |
Zeit für die Dekommitierung | Der Zeitstempel, an dem Speicher freigestellt wurde. |
Auswirkungen auf die Größe | Die Größe der ausstehenden Zuordnungen oder die Größe des Anfangs- und Endes des ausgewählten Zeitintervalls. Diese Größe passt sich basierend auf dem ausgewählten Ansichtsport an. Der Wert " Auswirkungsgröße " ist null, wenn alle von einem Prozess zugewiesenen Arbeitsspeicher am Ende des visualisierten Intervalls in WPA freigestellt werden . |
Größe | Die kumulative Summe aller Zuordnungen während des ausgewählten Zeitintervalls. |
Führen Sie diese Schritte aus, um MemoryTestApp.exe zu analysieren
Suchen Sie den Graphen "VirtualAlloc Commit Lifetimes" in der Speicherkategorie des Graph-Explorers.
Ziehen Und ablegen Sie die VirtualAlloc Commit-Lebensdauer auf die Registerkarte "Analyse ".
Organisieren Sie die Tabelle, um diese Spalten anzuzeigen. Klicken Sie mit der rechten Maustaste auf die Spaltenüberschriften, um Spalten hinzuzufügen oder zu entfernen.
Prozess
Auswirkungen auf den Typ
Commit-Stapel
Commitzeit und Dekommittzeit
Count
Auswirkungen auf Größe und Größe
Suchen Sie MemoryTestApp.exe in der Prozessliste.
Wenden Sie einen Filter an, um nur MemoryTestApp.exe auf dem Diagramm zu behalten.
- Klicken Sie mit der rechten Maustaste, und wählen Sie "Zu Auswahl filtern " aus.
Ihr Analyse-Ansichtsfenster sollte ungefähr so aussehen:
Im vorherigen Beispiel sind zwei Werte von Interesse:
Größe von 126 MB: Dies gibt an, dass MemoryTestApp.exe insgesamt 125 MB im Laufe der Lebensdauer zugewiesen haben. Es stellt die kumulative Summe aller VirtualAlloc-API-Aufrufe dar, die vom Prozess und dessen Abhängigkeiten vorgenommen wurden.
Auswirkungen auf die Größe von 0 MB: Dies gibt an, dass alle vom Prozess zugewiesenen Arbeitsspeicher bis zum Ende des derzeit analysierten Zeitintervalls freigestellt werden. Das System leidet nicht unter einer Erhöhung der Speichernutzung im Stetigen Zustand.
Schritt 2.1: Analysieren der Speichernutzung im Stationären Zustand
Wenn Sie die Speicherzuweisung untersuchen, sollten Sie versuchen, die Frage zu beantworten: "Warum wächst die Speichernutzung für dieses Szenario?" Im MemoryTestApp.exe Beispiel können Sie sehen, dass es ca. 10 MB beständiger Arbeitsspeicher am Anfang zugewiesen hat und dann auf 20 MB halbwegs erhöht wird.
Um dieses Verhalten zu untersuchen, verkleinern Sie den Zoom auf ungefähr das Zeitintervall, in dem der plötzliche Anstieg in der Mitte der Spur auftritt.
Ihre Ansicht sollte nun folgendermaßen aussehen:
Wie Sie sehen können, ist die Auswirkungsgröße jetzt 10 MB. Dies bedeutet, dass zwischen dem Start und dem Ende des Zeitintervalls, das analysiert wird, eine Erhöhung der Speichernutzung im Stationären Zustand von 10 MB besteht.
Sortieren Sie nach Der Auswirkung auf die Größe , indem Sie auf die Spaltenüberschrift klicken.
Erweitern Sie die Zeile MemoryTestApp.exe (in der Spalte "Prozess ").
Erweitern Sie die Zeile "Auswirkungen" (in der Spalte "Auswirkungstyp ").
Navigieren Sie durch den Prozess Commit Stack, bis Sie die Funktion finden, die 10 MB Speicher zugewiesen hat.
In diesem Beispiel weist die Hauptfunktion von MemoryTestApp.exe 10 MB Arbeitsspeicher in der Mitte der Arbeitslast zu, indem Sie VirtualAlloc direkt aufrufen. In der realen Welt sollte der Anwendungsentwickler bestimmen, ob die Zuordnung sinnvoll ist oder wenn der Code neu angeordnet werden könnte, um die Nutzung des Konstantenzustands zu minimieren.
Sie können nun den Viewport in WPA aufheben .
Schritt 2.2: Analysieren der vorübergehenden (oder spitzen) Speichernutzung
Bei der Untersuchung von Speicherzuweisungen sollten Sie versuchen, die Frage zu beantworten: "Warum gibt es einen vorübergehenden Spitzenwert in der Speichernutzung für diesen Teil des Szenarios?" Vorübergehende Zuordnungen verursachen Spitzen in der Speichernutzung und können zu Einer Fragmentierung führen und wertvolle Inhalte aus dem System-Standby-Cache verschieben, wenn speicherdruck vorhanden ist.
Im MemoryTest-Beispiel können Sie sehen, dass es 10 verschiedene Spitzen der Speichernutzung (von 10 MB) gleichmäßig über die Ablaufverfolgung verteilt gibt.
Verkleinern Sie den Zoom auf die letzten vier Spitzen, um sich auf einen kleineren Interessenbereich zu konzentrieren und Rauschen von nicht relevanten Verhaltensweisen zu reduzieren.
Ihre Ansicht sollte nun folgendermaßen aussehen:
Sortieren Sie nach Größe , indem Sie auf die Spaltenüberschrift klicken.
Erweitern Sie die Zeile MemoryTestApp.exe (in der Spalte "Prozess ").
Klicken Sie auf die Vorübergehende Zeile (in der Spalte "Auswirkungstyp").
- Dies sollte in blau allen Spitzen der Speichernutzung im Viewport hervorgehoben werden.
Beachten Sie den Wert der verschiedenen Spalten:
Anzahl = 4: Dies gibt an, dass während dieses Zeitintervalls vier vorübergehende Speicherzuweisungen vorgenommen wurden.
Auswirkungsgröße = 0 MB: Dies gibt an, dass alle vier vorübergehenden Speicherzuweisungen am Ende des Zeitintervalls freigestellt wurden.
Größe = 40 MB: Dies gibt an, dass die Summe aller vier vorübergehenden Speicherzuweisungen auf 40 MB Arbeitsspeicher beträgt.
Navigieren Sie zum Prozess commit Stack , bis Sie die Funktionen finden, die 40 MB Arbeitsspeicher zugewiesen haben.
In diesem Beispiel ruft die Hauptfunktion von MemoryTestApp.exe eine Funktion namens "Operation1" auf, die wiederum eine Funktion namens ManipulationTemporaryBuffer aufruft. Diese ManipulationTemporaryBuffer-Funktion ruft dann vier Mal VirtualAlloc an, erstellen und freisetzen einen 10 MB-Speicherpuffer jedes Mal. Die Puffer dauern jeweils nur 100 ms. Die Zuweisung und die freien Zeiten der Puffer werden durch die Spalten " Commit-Zeit " und " Zeitcommit" dargestellt.
In der realen Welt würde der Anwendungsentwickler bestimmen, ob diese vorübergehenden temporären Pufferzuweisungen erforderlich sind oder ob sie durch einen dauerhaften Speicherpuffer für den Vorgang ersetzt werden können.
Sie können nun den Viewport in WPAaufheben.
Schritt 3: Überprüfen der dynamischen Zuordnungen
Bisher hat sich die Analyse nur auf große Speicherzuweisungen konzentriert, die von der VirtualAlloc-API unterstützt werden. Der nächste Schritt besteht darin, festzustellen, ob es Probleme mit anderen kleinen Zuordnungen gibt, die vom Prozess vorgenommen werden, indem die Heap-Daten zunächst gesammelt wurden.
Die detaillierten Heap-Daten werden über das Diagramm "Heap Allocations" in WPA verfügbar gemacht. Andere interessante Spalten sind die folgenden:
Column | Beschreibung |
---|---|
Prozess | Der Name des Prozesses, der die Speicherzuweisung ausführt. |
Handle | Der Bezeichner des Heaps, der zum Dienst der Zuordnung verwendet wird. Heaps können erstellt werden, sodass mehrere Heap-Handle für den Prozess vorhanden sein könnten. |
Stapel | Der Aufrufstapel, der den Codepfad anzeigt, der zum zugewiesenen Speicher führt. |
Alloc-Zeit | Der Zeitstempel, an dem Speicher zugewiesen wurde. |
Auswirkungen auf die Größe | Die Größe der ausstehenden Zuordnungen oder der Unterschied zwischen dem Start- und Ende des ausgewählten Viewports. Diese Größe passt sich basierend auf dem ausgewählten Zeitintervall an. |
Größe | Die kumulative Summe aller Zuweisungen/Deallocations. |
Führen Sie diese Schritte aus, um MemoryTestApp.exe zu analysieren
Suchen Sie das Diagramm "Heap-Zuordnungen" in der Speicherkategorie des Graph-Explorers.
Ziehen Sie die Heap-Zuordnungen auf die Registerkarte "Analyse ".
Organisieren Sie die Tabelle, um diese Spalten anzuzeigen:
Prozess
Handle
Auswirkungen auf den Typ
Stapel
AllocTime
Count
Auswirkungen auf Größe und Größe
Suchen Sie MemoryTestApp.exe in der Prozessliste.
Wenden Sie einen Filter an, um nur MemoryTestApp.exe auf dem Diagramm zu behalten.
- Klicken Sie mit der rechten Maustaste, und wählen Sie "Zu Auswahl filtern " aus.
Ihre Ansicht sollte nun folgendermaßen aussehen:
In diesem Beispiel können Sie sehen, dass eine der Heaps im Laufe der Zeit kontinuierlich zu einer konstanten Rate erhöht wird. Es gibt 1200 Speicherzuweisungen für diesen Heap, die 130 KB des verwendeten Arbeitsspeichers bis zum Ende des Intervalls umfassen.
Zoomen Sie in ein kleineres Intervall (z. B. 10 Sekunden) in der Mitte der Ablaufverfolgung.
Erweitern Sie den Kopfhandpunkt , der die größte Anzahl von Zuordnungen anzeigt (wie in der Spalte "Auswirkungsgröße " dargestellt).
Erweitern Sie den Auswirkungstyp .
Navigieren Sie zum Prozessstapel , bis Sie die Funktion finden, die für die Zuweisung aller Speicher verantwortlich ist.
In diesem Beispiel ruft die Hauptfunktion von MemoryTestApp.exe eine Funktion namens InnerLoopOperation auf. Diese InnerLoopOperation-Funktion weist dann 40 Bytes Arbeitsspeicher 319 Mal über den neuen C++- Operator zu. Dieser Speicher bleibt bis zum Beenden des Prozesses zugewiesen.
In der realen Welt sollte der Anwendungsentwickler dann bestimmen, ob dieses Verhalten ein mögliches Speicherleck erfordert und das Problem beheben kann.
Schritt 4: Bereinigen des Testsystems
Sobald die Analyse abgeschlossen ist, sollten Sie die Registrierung bereinigen, um sicherzustellen, dass die Heap-Ablaufverfolgung für den Prozess deaktiviert ist. Führen Sie diesen Befehl in einem Eingabeaufforderungsfenster mit erhöhten Rechten aus:
reg delete "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /f