.NET Framework 4 以降では、同じプロセスで複数のバージョンの .NET Framework を並行して実行 (side-by-side 実行) できます。 プロファイラーは、この環境で実行するには side-by-side 対応である必要があります。プロファイリングを実行中のプロセスで複数のバージョンの .NET Framework をホストしない場合は、.NET Framework Version 2.0、.NET Framework 2.0 SP1、.NET Framework 3.0、.NET Framework 3.5、または .NET Framework 3.5 SP1 と連携するように設計されているプロファイラーを .NET Framework Version 4 で使用できます。 インプロセスの side-by-side プロファイリングを使用する方法の詳細については、「プロファイラーの互換性の設定」を参照してください。
side-by-side 対応
プロファイラーが side-by-side 対応であるといえるのは、複数のランタイムを読み込むアプリケーションを使用してもアクセス違反などの予期しない破損が発生しない場合です。 side-by-side 対応には、次のレベルのサポートが含まれます。
先頭プロファイリング。 プロセスに最初に読み込まれた共通言語ランタイム (CLR: Common Language Runtime) のバージョンがプロファイリングされ、それ以降に読み込まれた CLR のバージョンはプロファイリングされません。 プロファイラーは、その COM クラス ファクトリ オブジェクトで実行される CreateInstance の複数の呼び出しに対応できる必要がありますが、COM オブジェクトの複数のインスタンスでコールバックを同時にアクティブにして使用できる必要はありません。 プロファイラーは最初のクラス ファクトリの CreateInstance の呼び出しと Initialize コールバックの呼び出しを受け付けるだけで、残りは失敗します。
単一プロファイリング。 先頭プロファイリングと同様ですが、単に最初に読み込まれた CLR のバージョンをプロファイリングするのではなく、プロファイリングする CLR のバージョンをユーザーが選択できる点が異なります。
複数プロファイリング。 プロファイリングの対象として、1 つまたは複数 (場合によってはすべて) の CLR のバージョンをユーザーが選択します。 プロファイラーはそれらの CLR のバージョンのコールバックを使用し、Info 関数を呼び出して適切なバージョンに戻します。 この場合、どのランタイム項目 (関数、アプリケーション ドメイン、クラス、オブジェクトなど) がどの CLR に属するかをプロファイラーで追跡する必要があります。
![]() |
---|
.NET Framework 4 向けに設計するプロファイラーは side-by-side 対応にする必要があります。つまり、プロファイラーで、ICorProfilerCallback3 インターフェイスを実装する場合は、複数のランタイムが原因で予期しない破損が発生しないように、これらの方法 (先頭プロファイリング、単一プロファイリング、または複数プロファイリング) のいずれかを実装する必要があります。 |
複数プロファイリングをサポートするための要件
複数プロファイリングのオプションをサポートするには、プロファイラーは以下を実行できる必要があります。
グローバル関数の呼び出しを適切なランタイムに関連付ける。
さまざまな ID (ObjectID、FunctionID、ClassID、ModuleID、AssemblyID、AppDomainID など) を適切なランタイムに関連付け、特定のランタイムの ID が別のランタイムの ICorProfilerCallback(2,3) インターフェイスに渡されないようにする。 ただし、命令ポインターについては、任意のランタイムまたはネイティブ コードから ICorProfilerInfo::GetFunctionFromIP メソッドの任意のランタイムの実装に渡してもかまいません。
特定のランタイムから別のランタイムに渡される呼び出し履歴など、ランタイム間の相互作用を処理する。
同じプロセスで、アクティブな ICorProfilerCallback(2,3) を実装するクラスの複数のインスタンスを処理する。
プロファイラーでは、通常、グローバル関数の実装と複数のランタイムにまたがるデータを処理する 1 つのプロファイラー マネージャー オブジェクトを用意する必要があります。 次に例を示します。
すべてのランタイムの enter/leave/tailcall/FunctionIDMapperFunctionIDMapper 関数 コールバック。 プロファイラー マネージャー オブジェクトでは、通常、FunctionIDMapper2 または ICorProfilerInfo3::SetFunctionIDMapper2 の clientData パラメーターを使用して、対応するランタイムを確認します。
ランタイム間でのスタック ウォークとシャドウ スタック。
ランタイム間で調整されたログ記録。
また、ICorProfilerCallback インターフェイスを実装するプロファイラー オブジェクトも用意する必要があります。 このプロファイラー オブジェクトは、CLR によってアクティブなランタイムごとに 1 回初期化されます。 プロファイラーからアクセスする必要があるグローバル オブジェクトは、プロファイラー マネージャーだけです。 プロファイラーでは、ICorProfilerCallback の実装へのグローバルな参照を保持する必要はありません。これは、プロセスに複数のランタイムがある場合は、ICorProfilerCallback の実装の多数のインスタンスがアクティブになることがあるためです。
プロファイラーのアクティブ化
アクティブ化の主な作業は、プロファイラーとランタイム バージョンの関連付けです。
プロファイラーの起動
特定のプロセスにおいてすべてのランタイムでプロファイラーを起動する場合は、COR_PROFILER 環境変数と COR_ENABLE_PROFILING 環境変数を設定します (これは、.NET Framework 3.5 以前のバージョンの場合と同じ手順です)。
特定のランタイムでのみプロファイラーを起動する場合は、COR_PROFILER 環境変数と COR_ENABLE_PROFILING 環境変数を設定し、次のいずれかの操作を実行します。
クラス ファクトリ オブジェクトに対する CreateInstance の最初の呼び出しを除いて、すべて失敗にします (先頭プロファイリング)。
または
クラス ファクトリ オブジェクトに対する CreateInstance の呼び出しをすべて許可し、Initialize の呼び出しで、呼び出し元のランタイムのバージョンを確認します。 これには、次の操作の両方を実行する必要があります。
ICorProfilerInfo3 インターフェイスの CLR について QueryInterface メソッドを実行します。 失敗した場合、ランタイム バージョンは 1 または 2.0 です。 ICorProfilerInfo2 インターフェイスについて QueryInterface を実行すると、Version 2.0 のランタイムであるか Version 1 のランタイムであるかがわかります。
ICorProfilerInfo3 がサポートされている場合は、GetRuntimeInformation メソッドを呼び出して、プロファイリング対象のランタイムに関する詳細情報を取得します。
ランタイムのバージョンが確認されると、プロファイラーでそのランタイムをプロファイリングするかどうかを決定できます。 プロファイリングする場合、通常どおり初期化が続行されます。 プロファイリングしない場合は、Initialize からエラーが返されます。 .NET Framework 4 以降では、Windows アプリケーション イベント ログにエラーが記録されないように、プロファイラーは CORPROF_E_PROFILER_CANCEL_ACTIVATION HRESULT を返す場合があります。
プロファイラーのアタッチ
アタッチ トリガー プロセスでは、次の操作を実行します。
ICLRMetaHost::EnumerateLoadedRuntimes メソッドを使用して、ターゲット プロセスに読み込まれているランタイムを列挙し、目的のランタイムを見つけます。
ICLRMetaHost::EnumerateLoadedRuntimes メソッドから返される IEnumUnknown インターフェイスから ICLRRuntimeInfo インターフェイスを取得します。
CLSID_CLRProfiling および IID_ICLRProfiling を指定して ICLRRuntimeInfo インターフェイスで GetInterface を呼び出すことで、ICLRProfiling インターフェイスを取得します。
ICLRProfiling インターフェイスを通じて AttachProfiler メソッドを呼び出します。
プロファイラーのアタッチの詳細については、「プロファイラーのアタッチとデタッチ」を参照してください。