ICorProfilerInfo2::DoStackSnapshot メソッド
指定したスレッドのスタック上のマネージ フレームを走査し、コールバックを介してプロファイラーに情報を送信します。
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 関数をプロファイラーが呼び出しているときに、ロックを保持しないでください。 つまり、所有元のスレッドがガベージ コレクションを発生させる呼び出しを行う場合、ロックを保持しないでください。
個別の対象のスレッドのスタックを走査できるようにプロファイラーが作成したスレッドから DoStackSnapshot を呼び出すと、デッドロックが発生するおそれもあります。 作成したスレッドが特定の ICorProfilerInfo* メソッド (DoStackSnapshot を含む) に初めて入るときに、CLR により、スレッド単位の CLR 固有の初期化がそのスレッドに対して実行されます。 走査するスタックを持つ対象のスレッドがプロファイラーによって中断されており、その対象のスレッドがこのスレッド単位の初期化を実行するために必要なロックを所有している場合、デッドロックが発生します。 このデッドロックを回避するには、個別の対象のスレッドを走査するためにプロファイラーが作成したスレッドから DoStackSnapshot の初期呼び出しを実行します。このとき、最初に対象のスレッドが中断されないようにしてください。 この初期呼び出しにより、スレッド単位の初期化が確実にデッドロックなしで完了するようにできます。 DoStackSnapshot が正常に実行され、少なくとも 1 つのフレームを報告した場合、それ以降は、そのプロファイラーが作成したスレッドによって任意の対象のスレッドが中断され、その対象のスレッドのスタックを走査するために 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