コピーと固定

データをマーシャリングするときに、相互運用マーシャラはマーシャリングされるデータをコピーまたは固定できます。データをコピーすると、あるメモリ位置のデータのコピーが別のメモリ位置に配置されます。マネージ メモリからアンマネージ メモリにコピーされた値型と、参照渡しされた型の違いを次の図に示します。

値渡しされる値型と参照渡しされる値型

値と参照別に渡される値型

値渡しされるメソッド引数は、スタック上の値としてアンマネージ コードにマーシャリングされます。コピーのプロセスは直接的です。参照渡しされる引数は、ポインタとしてスタック上に渡されます。参照型も、値渡しまたは参照渡しできます。値渡しされる参照型がコピーまたは固定されるようすを次の図に示します。

値渡しされる参照型と参照渡しされる参照型

COM 相互運用

一時的な固定は、現在のメモリ位置にデータをロックします。したがって、共通言語ランタイムのガベージ コレクタによって、そのデータが再配置されることを回避できます。マーシャラはデータを固定することでコピーによるオーバーヘッドを減少させ、パフォーマンスを向上させます。マーシャリング プロセス中にデータがコピーされるのか固定されるのかは、そのデータの型によって決まります。一時的な固定は、String などのオブジェクトのマーシャリング中に自動的に実行されますが、GCHandle クラスを使って手動でメモリを一時的に固定することもできます。

書式指定された Blittable クラス

書式指定された blittable クラスは、マネージ メモリ内でもアンマネージ メモリ内でも、固定レイアウト (書式指定されている) と共通のデータ表現を持ちます。このような型をマーシャリングする必要がある場合は、ヒープ内のオブジェクトへのポインタが、呼び出し先に直接渡されます。呼び出し先はポインタによって参照されるメモリ位置の内容を変更できます。

Noteメモ :

パラメータに Out または In/Out のマークが付いている場合、呼び出し先はメモリの内容を変更できます。逆に、In としてマーシャリングするようにパラメータが設定されている場合、呼び出し先は内容の変更を避ける必要があります。In は書式指定された blittable 型に対する既定の設定です。同一クラスをタイプ ライブラリにエクスポートし、アパートメント間呼び出しのために使用した場合に、In オブジェクトを修正すると問題が発生します。

書式指定された Blittable でないクラス

書式指定されたblittable でないクラスは、固定レイアウト (書式指定されている) を持ちますが、マネージ メモリとアンマネージ メモリではデータ表現が異なります。次の状況では、データを変換する必要が生じる場合があります。

  • blittable でないクラスを値渡しでマーシャリングする場合、呼び出し先はデータ構造体のコピーへのポインタを受け取ります。

  • blittable でないクラスを参照渡しでマーシャリングする場合、呼び出し先はデータ構造体のコピーへのポインタを指すポインタを受け取ります。

  • InAttribute 属性が設定されている場合、このコピーは常にインスタンスの状態に初期化され、必要に応じてマーシャリングされます。

  • OutAttribute 属性が設定されている場合、制御が返されるときに常に状態がインスタンスにコピーされ、必要に応じてマーシャリングされます。

  • InAttributeOutAttribute が両方設定されている場合は、両方のコピーが必要になります。いずれか一方の属性が省略された場合、一方のコピーが省略されるため、処理が最適化されます。

参照型

参照型は値渡しまたは参照渡しできます。値渡しする場合は、型へのポインタがスタック上に渡されます。参照渡しする場合、型へのポインタを指すポインタがスタック上に渡されます。

参照型は、次のように条件付きで動作します。

  • 参照型が値渡しされ、その参照型のメンバのいずれかが非 blittable 型の場合、その型は 2 回変換されます。

    • 1 回目は引数をアンマネージ側に渡すとき。

    • 2 回目は呼び出しから制御が返されるとき。

    不要なコピーと変換を避けるために、これらの型は In パラメータとしてマーシャリングされます。呼び出し先による変更内容を呼び出し元が確認する必要がある場合には、引数に対して明示的に InAttribute 属性と OutAttribute 属性を適用する必要があります。

  • 参照型が値渡しされ、その参照型のメンバがすべて blittable 型の場合は、マーシャリング中にその参照型を固定できます。また、呼び出し先による型のメンバへの変更内容は呼び出し元にも反映されます。このような動作が必要な場合は、InAttributeOutAttribute を明示的に適用してください。これらの方向属性を使用しない場合は、相互運用マーシャラが方向情報をタイプ ライブラリにエクスポートしない (既定の In としてエクスポートします) ため、COM のアパートメント間マーシャリングで問題が生じることがあります。

  • 参照型を参照渡しする場合は、既定によりその型は In/Out としてマーシャリングされます。

System.String と System.Text.StringBuilder

アンマネージ コードにデータを値渡しまたは参照しでマーシャリングする場合、一般に、マーシャラはデータを 2 次バッファにコピーし (可能な場合には、コピー中に文字セットを変換)、そのバッファへの参照を呼び出し先に渡します。この参照が SysAllocString によって割り当てられた BSTR である場合を除き、参照は常に CoTaskMemAlloc によって割り当てられます。

文字列型を値渡しでマーシャリングする (Unicode 文字列など) ときの最適化処理として、マーシャラは新しいバッファに文字列型をコピーする代わりに、呼び出し先に対して内部 Unicode バッファ内のマネージ文字列への直接ポインタを渡します。

ヒント

文字列を値渡しする場合には、マーシャラから渡された参照を呼び出し先で変更しないようにしてください。変更した場合はマネージ ヒープが破損することがあります。

System.String を参照渡しする場合、マーシャラは呼び出しを実行する前にその文字列の内容を 2 次バッファにコピーします。次に呼び出しから制御が返されるときに、マーシャラはバッファの内容を新しい文字列の中にコピーします。この技法により、変更不可のマネージ文字列が変更されないことが保証されます。

System.Text.StringBuilder を値渡しする場合、マーシャラは StringBuilder の内部バッファへの参照を直接に呼び出し元に渡します。呼び出し元と呼び出し先で、バッファのサイズが一致する必要があります。呼び出し元は、適切な長さの StringBuilder を作成します。呼び出し先は、バッファのオーバーランが発生しないように必要な予防措置をとる必要があります。StringBuilder は、値渡しされる参照型は既定により In パラメータとして渡されるという規則の例外です。StringBuilder は常に In/Out として渡されます。

参照

概念

相互運用マーシャラによるメモリ管理
方向属性
相互運用マーシャリングの概要

その他の技術情報

既定のマーシャリングの動作