ICorProfilerInfo2::DoStackSnapshot-Methode
Durchläuft die verwalteten Frames im Stapel für den angegebenen Thread und sendet Informationen über einen Rückruf an den Profiler.
Syntax
HRESULT DoStackSnapshot(
[in] ThreadID thread,
[in] StackSnapshotCallback *callback,
[in] ULONG32 infoFlags,
[in] void *clientData,
[in, size_is(contextSize), length_is(contextSize)] BYTE context[],
[in] ULONG32 contextSize);
Parameter
thread
[in] Die ID des Zielthreads.
Das Übergeben von NULL in thread
ergibt eine Momentaufnahme des aktuellen Threads. Wenn ThreadID
von einem anderen Thread übergeben wird, hält die Common Language Runtime (CLR) diesen Thread an, führt die Momentaufnahme aus und setzt ihn fort.
callback
[in] Ein Zeiger auf die Implementierung der StackSnapshotCallback-Methode, die von der CLR aufgerufen wird, um dem Profiler Informationen zu jedem verwalteten Frame und jeder Ausführung nicht verwalteter Frames bereitzustellen.
Diese StackSnapshotCallback
-Methode wird vom Profiler-Writer implementiert.
infoFlags
[in] Ein Wert der COR_PRF_SNAPSHOT_INFO-Enumeration, der die Datenmenge angibt, die für jeden Frame von StackSnapshotCallback
zurückgegeben werden soll.
clientData
[in] Ein Zeiger auf die Clientdaten, der direkt an die Rückruffunktion StackSnapshotCallback
übergeben wird.
context
[in] Ein Zeiger auf die Win32-Struktur CONTEXT
, die zum Seeding des Stackwalks verwendet wird. Die Win32-Struktur CONTEXT
enthält Werte der CPU-Register und stellt den Zustand der CPU zu einem bestimmten Zeitpunkt dar.
Der Startwert hilft der CLR zu bestimmen, wo der Stackwalk beginnen soll, wenn der Anfang des Stapels nicht verwaltete Hilfscode ist. Andernfalls wird der Startwert ignoriert. Für einen asynchronen Walk muss ein Startwert angegeben werden. Wenn Sie einen synchronen Walk ausführen, ist kein Startwert erforderlich.
Der Parameter context
ist nur gültig, wenn das Flag COR_PRF_SNAPSHOT_CONTEXT im Parameter infoFlags
übergeben wurde.
contextSize
[in] Die Größe der CONTEXT
-Struktur, auf die vom Parameter context
verwiesen wird.
Bemerkungen
Das Übergeben von NULL in thread
ergibt eine Momentaufnahme des aktuellen Threads. Momentaufnahmen anderer Threads können nur erstellt werden, wenn der Zielthread zu diesem Zeitpunkt angehalten ist.
Wenn der Profiler den Stapel durchlaufen möchte, ruft er DoStackSnapshot
auf. Bevor die CLR von diesem Aufruf zurückkehrt, ruft sie StackSnapshotCallback
mehrmals auf, und zwar einmal für jeden verwalteten Frame (oder die Ausführung nicht verwalteter Frames) im Stapel. Wenn nicht verwaltete Frames gefunden werden, müssen Sie sie selbst durchlaufen.
Die Reihenfolge, in der der Stapel abgearbeitet wird, ist die umgekehrte Reihenfolge, in der die Frames in den Stapel gepusht wurden: (zuletzt gepushter) Blattframe zuerst, (zuerst gepushter) Hauptframe zuletzt.
Weitere Informationen darüber, wie Sie den Profiler zum Durchlaufen verwalteter Stapel programmieren, finden Sie unter Profiler Stack Walking in the .NET Framework 2.0: Basics and Beyond (Profilerstapel im .NET Framework 2.0: Grundlagen und mehr).
Ein Stackwalk kann synchron oder asynchron sein, wie in den folgenden Abschnitten erläutert.
Synchroner Stackwalk
Ein synchroner Stackwalk umfasst das Durchlaufen des Stapels des aktuellen Threads als Reaktion auf einen Rückruf. Es ist kein Seeding oder Anhalten erforderlich.
Sie tätigen einen synchronen Aufruf, wenn Sie als Reaktion auf den Aufruf einer der Methoden ICorProfilerCallback (oder ICorProfilerCallback2) Ihres Profilers durch die CLR DoStackSnapshot
aufrufen, um den Stapel des aktuellen Threads zu durchlaufen. Dies ist nützlich, wenn Sie feststellen möchten, wie der Stapel bei einer Benachrichtigung, wie z. B. ICorProfilerCallback::ObjectAllocated, aussieht. Sie rufen einfach DoStackSnapshot
in Ihrer ICorProfilerCallback
-Methode auf und übergeben NULL in den Parametern context
und thread
.
Asynchroner Stackwalk
Ein asynchroner Stackwalk umfasst das Durchlaufen des Stapels eines anderen Threads oder des aktuellen Threads, nicht als Reaktion auf einen Rückruf, sondern durch Hijacking des Anweisungszeigers des aktuellen Threads. Ein asynchroner Walk erfordert einen Startwert, wenn der Anfang des Stapels nicht verwalteter Code ist, der nicht Teil eines Plattformaufrufs (PInvoke) oder COM-Aufrufs ist, sondern Hilfscode in der CLR selbst. Beispielsweise ist Code, der die JIT-Kompilierung (Just-In-Time) oder Garbage Collection ausführt, Hilfscode.
Sie erhalten einen Startwert, indem Sie den Zielthread direkt anhalten und den Stapel selbst durchlaufen, bis Sie den obersten verwalteten Frame finden. Nachdem der Zielthread angehalten wurde, rufen Sie den aktuellen Registerkontext des Zielthreads ab. Ermitteln Sie als Nächstes, ob der Registerkontext auf nicht verwalteten Code verweist, indem Sie ICorProfilerInfo::GetFunctionFromIP aufrufen. Wenn eine FunctionID
gleich 0 (null) zurückgegeben wird, ist der Frame nicht verwalteter Code. Durchlaufen Sie nun den Stapel, bis Sie den ersten verwalteten Frame erreichen, und berechnen Sie dann den Seedkontext basierend auf dem Registerkontext für diesen Frame.
Rufen Sie DoStackSnapshot
mit Ihrem Seedkontext auf, um mit dem asynchronen Stackwalk zu beginnen. Wenn Sie keinen Startwert bereitstellen, überspringt DoStackSnapshot
ggf. verwaltete Frames am Anfang des Stapels, sodass Sie einen unvollständigen Stackwalk erhalten. Wenn Sie einen Startwert angeben, muss dieser auf von JIT kompilierten oder vom Native Image Generator (Ngen.exe) generierten Code verweisen. DoStackSnapshot
gibt andernfalls diesen Fehlercode zurück: CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX.
Asynchrone Stackwalks können leicht zu Deadlocks oder Zugriffsverletzungen führen, es sei denn, Sie befolgen diese Leitlinien:
Wenn Sie Threads direkt anhalten, denken Sie daran, dass nur ein Thread, der noch nie verwalteten Code ausgeführt hat, einen anderen Thread anhalten kann.
Blockieren Sie in Ihrem Rückruf von ICorProfilerCallback::ThreadDestroyed stets, bis der Stackwalk dieses Threads abgeschlossen ist.
Halten Sie keine Sperre aufrecht, während Ihr Profiler eine CLR-Funktion aufruft, die eine Garbage Collection auslösen kann. Das heißt, halten Sie keine Sperre aufrecht, wenn der besitzende Thread möglicherweise einen Aufruf tätigt, der eine Garbage Collection auslöst.
Es besteht auch das Risiko eines Deadlocks, wenn Sie DoStackSnapshot
in einem Thread aufrufen, den Ihr Profiler erstellt hat, damit Sie den Stapel eines separaten Zielthreads durchlaufen können. Wenn der von Ihnen erstellte Thread zum ersten Mal in bestimmte ICorProfilerInfo*
-Methoden (einschließlich DoStackSnapshot
) eintritt, führt die CLR für den jeweiligen Thread eine CLR-spezifische Initialisierung threadbezogen durch. Wenn Ihr Profiler den Zielthread angehalten hat, dessen Stapel Sie durchlaufen möchten, und dieser Zielthread eine Sperre besitzt, die für die Durchführung dieser Initialisierung threadbezogen erforderlich ist, tritt ein Deadlock auf. Um diesen Deadlock zu vermeiden, führen Sie einen anfänglichen Aufruf in DoStackSnapshot
in Ihrem vom Profiler erstellten Thread aus, um einen separaten Zielthread zu durchlaufen, aber halten Sie den Zielthread nicht zuerst an. Dieser anfängliche Aufruf stellt sicher, dass die threadbezogene Initialisierung ohne Deadlock abgeschlossen werden kann. Wenn DoStackSnapshot
erfolgreich ist und mindestens einen Frame meldet, ist es für den vom Profiler erstellten Thread ab diesem Zeitpunkt sicher, einen beliebigen Zielthread anzuhalten und DoStackSnapshot
aufzurufen, um den Stapel dieses Zielthreads zu durchlaufen.
Anforderungen
Plattformen: Informationen finden Sie unter Systemanforderungen.
Header: CorProf.idl, CorProf.h
Bibliothek: CorGuids.lib
.NET Framework-Versionen: Seit 2.0 verfügbar.