Interop (C++) のパフォーマンスに関する考慮事項

このトピックでは、マネージドとアンマネージドの相互運用の遷移が実行時のパフォーマンスに与える影響を軽減するためのガイドラインを示します。

Visual C++ では、Visual Basic や C# (P/Invoke) などの他の .NET 言語と同じ相互運用性メカニズムがサポートされますが、Visual C++ に固有の相互運用機能 (C++ Interop) のサポートも提供されます。 パフォーマンス クリティカルなアプリケーションでは、各相互運用手法のパフォーマンスへの影響を理解することが重要です。

使用する相互運用手法に関係なく、マネージド関数によってアンマネージド関数が呼び出されるたびにサンクと呼ばれる特殊な遷移シーケンスが必要になり、その逆でも必要になります。 これらのサンクは Microsoft C++ コンパイラによって自動的に挿入されますが、累積的に、これらの遷移はパフォーマンスの面でコストがかかる可能性があるという点を念頭に置く必要があります。

遷移の削減

相互運用のサンクのコストを回避または削減する方法の 1 つは、関連するインターフェイスをリファクタリングして、マネージドとアンマネージドの遷移を最小限に抑えることです。 頻繁に実行されるインターフェイスを対象にすることで、パフォーマンスが大幅に向上します。これは、マネージドとアンマネージドの境界を越えて頻繁に呼び出されるインターフェイスです。 たとえば、短いループでアンマネージド関数を呼び出すマネージド関数は、リファクタリングを行う最適な候補です。 ループ自体がアンマネージド側に移動される場合、またはアンマネージド呼び出しの代わりとなるマネージド呼び出しが作成される場合 (おそらく、マネージド側でデータをキューに入れてから、ループの後にすべてを同時にアンマネージド API にマーシャリングすることによって)、遷移の数を大幅に削減できます。

P/Invoke と C++ Interop

Visual Basic や C# などの .NET 言語の場合、ネイティブ コンポーネントと相互運用する際に指定されている方法は P/Invoke です。 P/Invoke は .NET Framework でサポートされているため、Visual C++ でもサポートされますが、Visual C++ では C++ Interop と呼ばれる独自の相互運用性のサポートも提供されます。 P/Invoke はタイプ セーフではないため、P/Invoke より C++ Interop が推奨されます。 その結果、エラーは主に実行時に報告されますが、C++ Interop は P/Invoke よりパフォーマンス上でも優れています。

どちらの手法でも、マネージド関数によってアンマネージド関数が呼び出されるたびに、いくつかの処理が発生する必要があります。

  • 関数呼び出しの引数は、CLR からネイティブ型にマーシャリングされます。

  • マネージドからアンマネージドへのサンクが実行されます。

  • アンマネージド関数が呼び出されます (引数のネイティブ バージョンを使用)。

  • アンマネージドからマネージドへのサンクが実行されます。

  • 戻り値の型と "out" または "in,out" 引数は、ネイティブ型から CLR 型にマーシャリングされます。

相互運用が機能するためにはマネージドとアンマネージドのサンクが必要ですが、必要なデータ マーシャリングは、関連するデータ型、関数シグネチャ、データの使用方法によって異なります。

C++ Interop によって実行されるデータ マーシャリングは、可能な限り最も単純な形式です。パラメーターは、シンプルにビット単位でマネージドとアンマネージドの境界を越えてコピーされます。変換は実行されません。 P/Invoke の場合、これはすべてのパラメーターが単純な blittable 型の場合にのみ当てはまります。 それ以外の場合、P/Invoke では、各マネージド パラメーターを適切なネイティブ型に変換する非常に堅牢な手順が実行されます。また、引数が "out" または "in,out" としてマークされている場合は、その逆が実行されます。

言い換えると、C++ Interop ではデータ マーシャリングの最速の方法が使われるのに対し、P/Invoke では最も堅牢な方法が使われます。 つまり、(C++ の一般的な方法での) C++ Interop では、既定で最適なパフォーマンスが提供され、プログラマーは、この動作が安全でなかったり適切でなかったりする場合の対処を担当します。

そのため、C++ Interop ではデータ マーシャリングを明示的に指定する必要がありますが、プログラマには、データの性質と使用方法を考えて、何が適切かを自由に決定できるという利点があります。 さらに、P/Invoke のデータ マーシャリングの動作もある程度はカスタマイズして変更できますが、C++ Interop ではデータ マーシャリングを呼び出し単位でカスタマイズできます。 これは P/Invoke では不可能です。

C++ Interop の詳細については、「C++ Interop (暗黙の PInvoke) の使用」を参照してください。

関連項目

混在 (ネイティブおよびマネージド) アセンブリ