次の方法で共有


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
[in] ターゲット スレッドの ID。

thread に null を渡すと、現在のスレッドのスナップショットが生成されます。 別のスレッドの ThreadID が渡された場合、共通言語ランタイム (CLR) はそのスレッドを中断し、スナップショットを実行して、再開します。

callback
[in] Stacksnapshotcallback メソッドの実装へのポインター。各マネージド フレームおよびアンマネージド フレームの各実行に関する情報をプロファイラーに提供するために CLR によって呼び出されます。

StackSnapshotCallback メソッドは、プロファイラー ライターによって実装されます。

infoFlags
[in] StackSnapshotCallback によって各フレームに返されるデータ量を指定する COR_PRF_SNAPSHOT_INFO 列挙体の値。

clientData
[in] StackSnapshotCallback コールバック関数を通じて直接渡されるクライアント データへのポインター。

context
[in] スタック ウォークのシードを設定するために使用される Win32 CONTEXT 構造体へのポインター。 Win32 CONTEXT 構造体には CPU レジスタの値が含まれており、特定の時点における CPU の状態を表します。

スタックの最上位がアンマネージド ヘルパー コードの場合、このシードにより CLR ではスタック ウォークの開始位置を決定できます。それ以外の場合、シードは無視されます。 非同期ウォークの場合はシードを指定する必要があります。 同期ウォークを実行する場合、シードは必要ありません。

context パラメーターは、COR_PRF_SNAPSHOT_CONTEXT フラグが infoFlags パラメーターで渡された場合にのみ有効です。

contextSize
[in] context パラメーターによって参照される CONTEXT 構造体のサイズ。

解説

thread に対して null を渡すと、現在のスレッドのスナップショットが生成されます。 ターゲット スレッドがその時点で中断されている場合にのみ、他のスレッドのスナップショットを取得できます。

プロファイラーでスタックをウォークする必要がある場合、DoStackSnapshot が呼び出されます。 その呼び出しから CLR が戻る前に、スタック上のマネージド フレーム (またはアンマネージド フレームの実行) ごとに 1 回ずつ、StackSnapshotCallback を複数回呼び出します。 アンマネージド フレームが検出されたら、それらを自分でウォークする必要があります。

スタックがウォークされる順序は、フレームがスタックにプッシュされた方法と逆になります。リーフ (最後にプッシュされた) フレームが最初で、メイン (最初にプッシュされた) フレームが最後です。

プロファイラーをプログラミングしてマネージド スタックをウォークする方法の詳細については、「.NET Framework 2.0 におけるプロファイラー スタック ウォーク: その基本と発展」を参照してください。

次のセクションで説明するように、スタック ウォークは同期または非同期にすることができます。

同期スタック ウォーク

同期スタック ウォークでは、コールバックへの応答として現在のスレッドのスタックをウォークする必要があります。 シードや中断は必要ありません。

同期呼び出しを行うのは、プロファイラーの ICorProfilerCallback (または ICorProfilerCallback2) メソッドのいずれかを呼び出す CLR に応答して、DoStackSnapshot を呼び出して現在のスレッドのスタックをウォークする場合です。 これは、ICorProfilerCallback::ObjectAllocatedなどの通知があったとき、スタックがどのように見えるかを確認する場合に便利です。 DoStackSnapshot は、ICorProfilerCallback メソッド内で、contextパラメーターと thread パラメーターに null を渡して呼び出します。

非同期スタック ウォーク

非同期スタック ウォークでは、別のスレッドのスタックをウォークしたり、コールバックへの応答ではなく現在のスレッドの命令ポインターをハイジャックすることによって現在のスレッドのスタックをウォークしたりすることが必要になります。 スタックの最上位が、プラットフォーム呼び出し (PInvoke) または COM 呼び出しの一部ではなく、CLR 自体のヘルパー コードであるアンマネージド コードの場合、非同期ウォークにはシードが必要です。 たとえば、Just-In-Time (JIT) コンパイルまたはガベージ コレクションを実行するコードはヘルパー コードです。

シードの取得は、ターゲット スレッドを直接中断し、最上位のマネージド フレームが見つかるまで自分でスタックをウォークすることによって行います。 ターゲット スレッドが中断された後、ターゲット スレッドの現在のレジスタ コンテキストを取得します。 次に、ICorProfilerInfo::GetFunctionFromIP を呼び出すことによって、レジスタ コンテキストがアンマネージド コードを指しているかどうかを確認します。0 と等しい FunctionID を返す場合、フレームはアンマネージド コードです。 次に、最初のマネージド フレームに達するまでスタックをウォークし、そのフレームのレジスタ コンテキストに基づいてシード コンテキストを計算します。

シード コンテキストを使用して DoStackSnapshot を呼び出し、非同期スタック ウォークを開始します。 シードを指定しないと、DoStackSnapshot ではスタックの一番上にあるマネージド フレームがスキップされ、その結果、不完全なスタック ウォークになります。 シードを指定する場合は、JIT コンパイルされたコードまたはネイティブ イメージ ジェネレーター (Ngen.exe) で生成されたコードをポイントする必要があります。それ以外の場合、DoStackSnapshot はエラーコード CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX を返します。

非同期スタック ウォークは、次のガイドラインに従わないと、簡単にデッドロックまたはアクセス違反を引き起こす場合があります。

  • スレッドを直接中断する場合は、マネージド コードを実行したことのないスレッドだけが別のスレッドを中断できることに注意してください。

  • ICorProfilerCallback::ThreadDestroyed コールバックは、そのスレッドのスタック ウォークが完了するまで常にブロックします。

  • ガベージ コレクションをトリガーできる CLR 関数がプロファイラーで呼び出されている間は、ロックを保持しないでください。 つまり、所有スレッドによって、ガベージ コレクションをトリガーする呼び出しが実行される可能性がある場合、ロックを保持しないでください。

また、別個のターゲット スレッドのスタックをウォークできるようにプロファイラーによって作成されたスレッドから DoStackSnapshot を呼び出した場合も、デッドロックのリスクがあります。 作成したスレッドが特定の ICorProfilerInfo* メソッド (DoStackSnapshot を含む) に初めて入ったとき、CLR はそのスレッドに対して、スレッドごとの CLR 固有の初期化を実行します。 ウォークしようとしているスタックを含むターゲット スレッドがプロファイラーによって中断され、そのターゲット スレッドが、このスレッドごとの初期化を実行するために必要なロックを偶然所有していた場合、デッドロックが発生します。 このデッドロックを回避するには、プロファイラーによって作成されたスレッドから DoStackSnapshot への最初の呼び出しを行って別個のターゲット スレッドをウォークするようにし、ターゲット スレッドを最初に中断しないようにします。 この最初の呼び出しにより、デッドロックすることなくスレッドごとの初期化が完了できるようになります。 DoStackSnapshot が成功し、少なくとも 1 つのフレームを報告した場合、その時点以降は、プロファイラーによって作成されたスレッドは、任意のターゲット スレッドを中断し、DoStackSnapshot を呼び出して、そのターゲット スレッドのスタックを安全にウォークできるようになります。

必要条件

:システム要件」を参照してください。

ヘッダー : CorProf.idl、CorProf.h

ライブラリ: CorGuids.lib

.NET Framework のバージョン: 2.0 以降で使用可能

関連項目