更新 : 2007 年 11 月
指定したスレッドのスタック上のマネージ フレームを走査し、コールバックを介してプロファイラに情報を送信します。
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
[入力] 対象のスレッドの ID。thread で null を渡すと、現在のスレッドのスナップショットが作成されます。別のスレッドの ThreadID を渡すと、共通言語ランタイム (CLR: Common Language Runtime) はそのスレッドを中断し、スナップショットを実行した後、再開します。
callback
[入力] StackSnapshotCallback メソッドの実装へのポインタ。このメソッドは CLR によって呼び出され、各マネージ フレームおよびアンマネージ フレームの各実行に関する情報をプロファイラに提供します。StackSnapshotCallback メソッドは、プロファイラ ライタによって実装されます。
infoFlags
[入力] COR_PRF_SNAPSHOT_INFO 列挙体の値。StackSnapshotCallback によってフレームごとに返されるデータの量を指定します。clientData
[入力] クライアント データへのポインタ。StackSnapshotCallback コールバック関数に直接渡されます。context
[入力] Win32 CONTEXT 構造体へのポインタ。スタック ウォークをシードするために使用されます。Win32 CONTEXT 構造体には CPU レジスタの値が格納され、特定の瞬間の CPU の状態を表します。スタックの上部がアンマネージ ヘルパー コードの場合、CLR はシードによりスタック ウォークを開始する場所を決定します。それ以外の場合、シードは無視されます。シードは非同期ウォークに対して指定する必要があります。同期ウォークを実行する場合、シードは不要です。
context パラメータは、COR_PRF_SNAPSHOT_CONTEXT フラグが infoFlags パラメータに渡される場合のみ有効です。
contextSize
[入力] CONTEXT 構造体のサイズ。context パラメータによって参照されます。
解説
thread で null を渡すと、現在のスレッドのスナップショットが作成されます。対象のスレッドがその時点で中断されている場合のみ、他のスレッドのスナップショットが取られることがあります。
プロファイラがスレッドを走査する場合、DoStackSnapshot が呼び出されます。CLR はその呼び出しから戻る前に、スタック上のマネージ フレーム (またはアンマネージ フレームの実行) ごとに 1 回、StackSnapshotCallback を繰り返し呼び出します。アンマネージ フレームが検出された場合、ユーザー自身がアンマネージ フレームを走査する必要があります。
スタックが走査される順序は、フレームがスタックにプッシュされる順序とは逆になります。つまり、リーフ (最後にプッシュされた) フレームが最初に走査され、メイン (最初にプッシュされた) フレームが最後に走査されます。
プロファイラでマネージ スタックを走査するようにプログラミングする方法の詳細については、MSDN ライブラリの「.NET Framework 2.0 におけるプロファイラ スタック ウォーク: その基本と発展」を参照してください。
以下のセクションで説明するように、スタック ウォークは同期でも非同期でも実行できます。
同期スタック ウォーク
同期スタック ウォークでは、コールバックに応じて現在のスレッドのスタックが走査されます。シードまたは中断は不要です。
プロファイラの ICorProfilerCallback メソッド (または ICorProfilerCallback2 メソッド) の 1 つを呼び出す CLR に応じて、DoStackSnapshot を呼び出して現在のスレッドのスタックを走査するときに、同期呼び出しを行います。これは、ICorProfilerCallback::ObjectAllocated などの通知のときにスタックがどのようになるかを確認する場合に便利です。ICorProfilerCallback メソッド内から DoStackSnapshot を呼び出し、context パラメータおよび thread パラメータで null を渡します。
非同期スタック ウォーク
非同期スタック ウォークでは、コールバックに応じてではなく、現在のスレッドの命令ポインタをハイジャックすることで、別のスレッドのスタックの走査、または現在のスレッドのスタックの走査が必要になります。非同期ウォークでは、スタックの上部がプラットフォーム呼び出し (PInvoke) または COM 呼び出しの一部ではなく CLR 自体のヘルパー コードであるアンマネージ コードの場合、シードが必要になります。たとえば、Just-In-Time (JIT) コンパイルまたはガベージ コレクションを実行するコードは、ヘルパー コードです。
最上位のマネージ フレームが見つかるまで、対象のスレッドを直接中断し、ユーザー自身がスタックを走査することで、シードを取得します。対象のスレッドが中断された後、対象のスレッドの現在のレジスタ コンテキストを取得します。次に、ICorProfilerInfo::GetFunctionFromIP を呼び出して、レジスタ コンテキストがアンマネージ コードを指すかどうかを調べます。返された FunctionID が 0 の場合、フレームはアンマネージ コードです。ここで、最初のマネージ フレームに到達するまでスタックを走査した後、そのフレームのレジスタ コンテキストに基づいてシード コンテキストを計算します。
非同期スタック ウォークを開始するために、シード コンテキストを使用して DoStackSnapshot を呼び出します。シードを指定しない場合、DoStackSnapshot はスタックの上部でマネージ フレームをスキップする可能性があるため、スタック ウォークが不完全になります。シードを指定した場合、シードは JIT コンパイル コードまたはネイティブ イメージ ジェネレータ (Ngen.exe) 生成コードを指す必要があります。それ以外の場合、DoStackSnapshot はエラー コード (CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX) を返します。
次のガイドラインに従わない場合、非同期スタック ウォークでは、デッドロックまたはアクセス違反が発生しやすくなります。
スレッドを直接中断する場合、別のスレッドを中断できるのは、マネージ コードを実行したことがないスレッドだけです。
そのスレッドのスタック ウォークが完了するまで、ICorProfilerCallback::ThreadDestroyed コールバックで常にブロックします。
ガベージ コレクションを発生させる可能性がある CLR 関数をプロファイラが呼び出しているときに、ロックを保持しないでください。つまり、所有元のスレッドがガベージ コレクションを発生させる呼び出しを行う場合、ロックを保持しないでください。
必要条件
プラットフォーム : 「.NET Framework システム要件」を参照
ヘッダー : CorProf.h
ライブラリ : CorProf.idl
.NET Framework のバージョン : 3.5 SP1、3.5、3.0 SP1、3.0、2.0 SP1、2.0