共用方式為


ICorProfilerInfo2::DoStackSnapshot 方法

在堆疊上針對指定的執行緒查核 Managed 框架行程,並且透過回呼,將資訊傳送至分析工具。

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);

參數

  • thread
    [in] 目標執行緒 ID。

    將 null 傳入 thread 會產生目前執行緒的快照。 如果傳遞不同執行緒的 ThreadID,則 Common Language Runtime (CLR) 會暫止該執行緒、執行該快照並繼續。

  • callback
    [in] StackSnapshotCallback 方法之實作的指標,CLR 會呼叫這個方法,為分析工具提供每個 Managed 框架和每次執行 Unmanaged 框架的資訊。

    StackSnapshotCallback 方法是由分析工具寫入器實作。

  • infoFlags
    [in] COR_PRF_SNAPSHOT_INFO 列舉型別 (Enumeration) 的值,這個值會指定 StackSnapshotCallback 要對每個框架傳遞回的資料量。

  • clientData
    [in] 用戶端資料的指標,此資訊會直接傳遞至 StackSnapshotCallback 回呼函式。

  • context
    [in] Win32 CONTEXT 結構的指標,這個結構用來執行堆疊查核行程。 Win32 CONTEXT 結構包含 CPU 暫存器的值,並且表示特定時間的 CPU 狀態。

    如果堆疊最上方是 Unmanaged Helper 程式碼,種子會協助 CLR 判斷從何處開始堆疊查核行程,否則會忽略種子。 您必須針對非同步查核行程提供種子。 如果是執行同步查核行程,則不需要種子。

    只有在 COR_PRF_SNAPSHOT_CONTEXT 旗標已傳入 infoFlags 參數時,context 參數才是有效的。

  • contextSize
    [in] CONTEXT 結構的大小,這個結構由 context 參數所參考。

備註

對 thread 傳遞 null 會產生目前執行緒的快照。 只有在目標執行緒暫止時,才能產生其他執行緒的快照。

當分析工具要執行堆疊查核行程時,它會呼叫 DoStackSnapshot。 CLR 從該呼叫傳回之前,它會多次呼叫 StackSnapshotCallback,針對堆疊上的每個 Managed 框架 (或每次執行 Unmanaged 框架) 各呼叫一次。 遇到 Unmanaged 框架時,您必須自行查核它們的行程。

堆疊查核行程的順序是框架推入至堆疊的相反順序:(最後推入的) 分葉框架最先,而 (最先推入的) 主框架最後。

如需如何將分析工具設計為查核 Managed 堆疊的詳細資訊,請參閱 MSDN Library 中的<.NET Framework 2.0 中分析工具堆疊查核行程:基本與進一步資訊>(英文)。

堆疊查核行程 (Stack Walk) 可以是同步或非同步,如下列各節所述。

同步堆疊查核行程

同步堆疊查核行程包含為回應回呼而對目前執行緒進行的堆疊查核行程。 它不需要執行或暫止。

為了回應 CLR 呼叫分析工具的其中一個 ICorProfilerCallback (或 ICorProfilerCallback2) 方法,您呼叫 DoStackSnapshot 執行目前執行緒的堆疊查核行程時,執行了同步呼叫。 當您要查看看似告知的堆疊時 (例如 ICorProfilerCallback::ObjectAllocated),這會很有幫助。 您剛剛從 ICorProfilerCallback 方法呼叫 DoStackSnapshot,並將 null 傳入context 和 thread 參數。

非同步堆疊查核行程

非同步堆疊查核行程不是為了回應回呼,而是藉由挾持目前執行緒的指令指標,來執行不同執行緒的堆疊查核行程,或執行目前執行緒的堆疊查核行程。 如果堆疊最上方的 Unmanaged 程式碼不是平台叫用 (PInvoke) 或 COM 呼叫的一部分,而是 CLR 本身的 Helper 程式碼,則非同步查核行程需要種子。 例如,執行 Just-In-Time (JIT) 編譯或記憶體回收的程式碼就是 Helper 程式碼。

您可以藉由直接暫止目標執行緒,並且自行執行其堆疊查核行程,直到找到最上方的 Managed 框架,來取得種子。 暫止目標執行緒之後,取得目標執行緒的現行暫存器內容。 下一步,呼叫 ICorProfilerInfo::GetFunctionFromIP,判斷暫存器內容是否指向 Unmanaged 程式碼,如果傳回等於零的 FunctionID,框架就是 Unmanaged 程式碼。 現在,執行堆疊查核行程,直到到達第一個 Managed 框架,然後根據該框架的暫存器內容來計算種子內容。

以種子內容來呼叫 DoStackSnapshot,開始非同步堆疊查核行程。 如果您沒有提供種子,DoStackSnapshot 可能會略過堆疊最上方的 Managed 框架,因此會提供您不完整的堆疊查核行程。 如果提供種子,它必須指向 JIT 編譯或原生映像產生器 (Ngen.exe) 產生的程式碼,否則 DoStackSnapshot 會傳回失敗碼 CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX。

非同步查核行程很可能造成死結 (Deadlock) 或存取違規,因此務必依照下列方針執行:

  • 當您直接暫止執行緒時,請記住,只有從未執行 Managed 程式碼的執行緒才能暫止另一個執行緒。

  • 在完成該執行緒的堆疊查核行程之前,一律在 ICorProfilerCallback::ThreadDestroyed 回呼中封鎖。

  • 當分析工具呼叫會觸發記憶體回收的 CLR 函式時,請勿保留鎖定。 也就是說,如果主控執行緒呼叫可能會觸發記憶體回收,請勿保留鎖定。

如果您從您的程式碼剖析工具已建立的執行緒呼叫 DoStackSnapshot,以便能夠查核各別目標執行緒的堆疊,也會有產生死結的風險。 您第一次建立的執行緒會輸入特定 ICorProfilerInfo* 方法 (包括 DoStackSnapshot),CLR 會在該執行緒執行個別執行緒的特定 CLR 初始化。 如果您的程式碼剖析工具已暫止您所嘗試查核其堆疊的目標執行緒,而且如果該目標執行緒剛好擁有鎖定,此鎖定又必要於執行這個根據執行緒的初始化,就會形成死結。 若要避免這個死結,請從程式碼剖析工具建立的執行緒初次呼叫 DoStackSnapshot 來查核個別目標執行緒,而不要先暫止目標執行緒。 這個初始呼叫可確保每個執行緒初始化可以完成而沒有死結。 如果 DoStackSnapshot 成功並報告至少一個圖文框,在該時間點之後,程式碼剖析工具即可安全建立執行緒以暫止任何目標執行緒,並呼叫 DoStackSnapshot 以執行該目標執行緒的堆疊查核行程。

需求

**平台:**請參閱 .NET Framework 系統需求

**標頭:**CorProf.idl、CorProf.h

**程式庫:**CorGuids.lib

**.NET Framework 版本:**4、3.5 SP1、3.5、3.0 SP1、3.0、2.0 SP1、2.0

請參閱

參考

ICorProfilerInfo 介面

ICorProfilerInfo2 介面