Ereignisse für benutzerdefinierte native ETW-Heaps
Visual Studio enthält eine Vielzahl von profiling and diagnostic tools (Profilerstellungs- und Diagnosetools), einschließlich einer nativen Speicherprofilerstellung. Dieser Profiler hängt sich an ETW-Ereignisse vom Heap-Anbieter, und bietet eine Analyse, wie Speicher zugeordnet und verwendet wird. Dieses Tool kann standardmäßig nur aus dem standardmäßigen Windows-Heap vorgenommene Zuordnungen analysieren. Zuordnungen außerhalb dieses nativen Heap werden nicht angezeigt.
Es gibt viele Fälle, in denen Sie Ihren eigenen benutzerdefinierten Heap verwenden und den Zuordnungsaufwand aus dem Standard-Heap vermeiden möchten. Beispielsweise können Sie VirtualAlloc verwenden, um eine große Menge an Speicher am Anfang der App oder des Spiels zuzuordnen, und anschließend Ihre eigenen Blöcke in dieser Liste zu verwalten. In diesem Szenario würde das Speicherprofilerstellungstool nur diese anfänglichen Zuordnung und nicht die benutzerdefinierte Verwaltung innerhalb des Speicherblocks finden. Jedoch können Sie mithilfe des benutzerdefinierten nativen Heap-ETW-Anbieters dafür sorgen,dass das Tool alle Zuordnungen kennt, die Sie außerhalb des Standard-Heaps vornehmen.
In einem Projekt wie dem Folgenden, in dem MemoryPool
ein benutzerdefinierter Heap ist, würden Sie z.B. nur eine einzige Zuordnung auf dem Windows-Heap sehen:
class Foo
{
public:
int x, y;
};
...
// MemoryPool is a custom managed heap, which allocates 8192 bytes
// on the standard Windows Heap named "Windows NT"
MemoryPool<Foo, 8192> mPool;
// the "allocate" method requests memory from the pool created above
// and is cast to an object of type Foo, shown above
Foo* pFoo1 = (Foo*)mPool.allocate();
Foo* pFoo2 = (Foo*)mPool.allocate();
Foo* pFoo3 = (Foo*)mPool.allocate();
Eine Momentaufnahme aus dem Speicherauslastungstool ohne benutzerdefinierte Heap-Nachverfolgung würde nur einfach die einzelne 8.192 Byte-Zuordnung und keine der benutzerdefinierten Zuordnungen, die vom Pool vorgenommen wurden, anzeigen:
Sie können dieses Tool auch zum Nachverfolgen der Speicherauslastung in Ihrem benutzerdefinierten Heap verwenden, indem Sie die folgenden Schritte ausführen.
Verwendung
Diese Bibliothek kann problemlos in C und C++ verwendet werden.
Fügen Sie den Header für den benutzerdefinierten Heap-ETW-Anbieter ein:
#include <VSCustomNativeHeapEtwProvider.h>
Hinzufügen des
__declspec(allocator)
-Decorator für alle Funktionen in Ihrem benutzerdefinierten Heapmanager, das einen Zeiger auf den neu zugeordneten Heapspeicher zurückgibt. Dieser Decorator ermöglicht es dem Tool, den Typ des zurückgegebenen Speichers korrekt zu identifizieren. Beispiel:__declspec(allocator) void *MyMalloc(size_t size);
Hinweis
Dieser Decorator informiert den Compiler, dass diese Funktion ein Aufruf an eine Zuweisung ist. Jeder Aufruf der Funktion wird die Adresse der Aufrufsite, die Größe der Aufrufanweisung und die TypeId des neuen Objekts zu einem neuen
S_HEAPALLOCSITE
-Symbol ausgeben. Wenn eine Aufrufliste zugeordnet ist, wird Windows ein ETW-Ereignis mit diesen Informationen ausgeben. Der Speicherprofilerstellungstool führt die Aufrufliste dazu, eine Rückgabeadresse entsprechend desS_HEAPALLOCSITE
-Symbols zu suchen. Die TypeId-Informationen im Symbol wird verwendet, um den Laufzeittyp der Zuordnung anzuzeigen.Kurz gesagt bedeutet dies, dass ein Aufruf, der wie
(B*)(A*)MyMalloc(sizeof(B))
aussieht, im Tool alsB
-Typ angezeigt wird, nichtvoid
oderA
.Erstellen Sie für C++ das
VSHeapTracker::CHeapTracker
-Objekt, das einen Namen für den Heap bereitstellt, der im Profilerstellungstool angezeigt werden wird:auto pHeapTracker = std::make_unique<VSHeapTracker::CHeapTracker>("MyCustomHeap");
Wenn Sie C verwenden, verwenden Sie stattdessen.die
OpenHeapTracker
-Funktion. Diese Funktion gibt ein Handle zurück, das Sie verwenden, wenn Sie andere Nachverfolgungsfunktionen aufrufen:VSHeapTrackerHandle hHeapTracker = OpenHeapTracker("MyHeap");
Rufen Sie beim Zuweisen von Speicher mithilfe der benutzerdefinierte Funktion die
AllocateEvent
(C++)- oderVSHeapTrackerAllocateEvent
(C)-Methode auf, und übergeben Sie den Zeiger an den Speicher und ihre Größe, um die Zuordnung zu verfolgen:pHeapTracker->AllocateEvent(memPtr, size);
oder
VSHeapTrackerAllocateEvent(hHeapTracker, memPtr, size);
Wichtig
Vergessen Sie nicht, Ihre benutzerdefinierte Zuweisungsfunktion mit dem weiter oben beschriebenen
__declspec(allocator)
-Decorator-Element zu markieren.Rufen Sie beim Freigeben von Speicher mithilfe der benutzerdefinierte Funktion die
DeallocateEvent
(C++)- oderVSHeapTracerDeallocateEvent
(C)-Funktion auf und übergeben Sie den Zeiger an den Speicher, um die Freigabe zu verfolgen:pHeapTracker->DeallocateEvent(memPtr);
oder:
VSHeapTrackerDeallocateEvent(hHeapTracker, memPtr);
Rufen Sie beim Neuzuordnen von Speicher mithilfe der benutzerdefinierte Funktion die
ReallocateEvent
(C++)- oderVSHeapReallocateEvent
(C)-Methode auf, und übergeben Sie einen Zeiger an den neuen Speicher, an die Größe der Zuordnung und einen Zeiger an den alten Speicher:pHeapTracker->ReallocateEvent(memPtrNew, size, memPtrOld);
oder:
VSHeapTrackerReallocateEvent(hHeapTracker, memPtrNew, size, memPtrOld);
Verwenden Sie schlussendlich den
CHeapTracker
-Destruktor, entweder manuell oder über standardmäßige Bereichsregeln, oder dieCloseHeapTracker
-Funktion in C, um die benutzerdefinierte Heap-Nachverfolgung in C++ zu schließen und zu bereinigen:delete pHeapTracker;
oder:
CloseHeapTracker(hHeapTracker);
Nachverfolgen der Arbeitsspeicherauslastung
Mit diesen Aufrufen kann Ihr benutzerdefinierter Heapverbrauch jetzt mithilfe des Standard-Speicherauslastungs-Tools in Visual Studio nachverfolgt werden. Weitere Informationen zur Verwendung dieses Tools finden Sie unter der Speicherauslastungs-Dokumentation. Stellen Sie sicher, dass Sie die Heap-Profilerstellung mit Momentaufnahmen aktiviert haben, andernfalls wird Ihr benutzerdefinierter Heapverbrauch nicht angezeigt.
Verwenden Sie zum Anzeigen Ihrer benutzerdefinierten Heap-Nachverfolgung den Heap-Dropdown, der sich in der oberen rechten Ecke des Snapshot-Fensters befindet, um die Anzeige von NT-Heap in Ihren eigenen zuvor genannten Heap zu ändern.
Mithilfe des obigen Codebeispiels, mit MemoryPool
zum Erstellen eines VSHeapTracker::CHeapTracker
-Objekts, und unserer eigenen allocate
-Methode, die nun die AllocateEvent
-Methode aufruft, können Sie das Ergebnis der benutzerdefinierten Zuordnung sehen, die drei Instanzen mit insgesamt 24 Bytes zeigt, alle sind vom Typ Foo
.
Das Standardheap NT-Heap sieht genauso aus wie vorher, außer dass das CHeapTracker
-Objekt hinzugefügt wurde.
Wie bei dem standardmäßigen Windows-Heap, können Sie dieses Tool auch verwenden, um Momentaufnahmen zu vergleichen und um nach Verlusten und Beschädigung in Ihrem benutzerdefinierten Heap zu suchen, das in der Hauptdokumentation Speicherauslastung beschrieben wird.
Tipp
Visual Studio enthält auch ein Speicherauslastungstool im Leistungsprofilerstellungs-Toolset, das in der Menüoption Debuggen>Leistungsprofilerstellung oder über die Tastenkombination ALT+F2 aktiviert wird. Diese Funktion enthält keine Heap-Nachverfolgung und wird Ihren benutzerdefinierten Heap nicht wie hier beschrieben anzeigen. Nur das Diagnosetools-Fenster, das im Menü Debuggen>Windows>Diagnosetools anzeigen oder mit der Tastenkombination STRG+ALT+F2 aktiviert werden kann, enthält diese Funktion.
Zugehöriger Inhalt
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für