コピーと固定Copying and Pinning

データをマーシャリングするときに、相互運用マーシャラーはマーシャリングされるデータをコピーまたは固定できます。When marshaling data, the interop marshaler can copy or pin the data being marshaled. データをコピーすると、あるメモリ位置のデータのコピーが別のメモリ位置に配置されます。Copying the data places a copy of data from one memory location in another memory location. マネージド メモリからアンマネージド メモリへの値型のコピーと、参照渡しされる型のコピーの違いを次の図に示します。The following illustration shows the differences between copying a value type and copying a type passed by reference from managed to unmanaged memory.

値型と参照型がどのようにコピーされるかを示す図。

値渡しされるメソッド引数は、スタック上の値としてアンマネージ コードにマーシャリングされます。Method arguments passed by value are marshaled to unmanaged code as values on the stack. コピーのプロセスは直接的です。The copying process is direct. 参照渡しされる引数は、ポインターとしてスタック上に渡されます。Arguments passed by reference are passed as pointers on the stack. 参照型も値渡しと参照渡しが行われます。Reference types are also passed by value and by reference. 次の図に示されているように、値渡しされる参照型はコピーまたは固定されます。As the following illustration shows, reference types passed by value are either copied or pinned:

値渡しされる参照型と参照渡しされる参照型を示す図。

固定では一時的に現在のメモリ位置でデータをロックします。したがって、共通言語ランタイムのガベージ コレクターによって、そのデータが再配置されることを回避できます。Pinning temporarily locks the data in its current memory location, thus keeping it from being relocated by the common language runtime's garbage collector. マーシャラーはデータを固定することでコピーのオーバーヘッドを減らし、パフォーマンスを向上させます。The marshaler pins data to reduce the overhead of copying and enhance performance. マーシャリング プロセス中にデータがコピーされるか固定されるかは、そのデータの型によって決まります。The type of the data determines whether it is copied or pinned during the marshaling process. 固定は String などのオブジェクトのマーシャリング中に自動的に実行されますが、GCHandle クラスを使用して手動でメモリを固定することもできます。Pinning is automatically performed during marshaling for objects such as String, however you can also manually pin memory using the GCHandle class.

書式指定された blittable クラスFormatted Blittable Classes

書式指定された blittable クラスは、マネージド メモリとアンマネージド メモリの両方で、固定レイアウト (書式指定されている) と共通のデータ表現を持ちます。Formatted blittable classes have fixed layout (formatted) and common data representation in both managed and unmanaged memory. このような型でマーシャリングが必要な場合は、ヒープ内のオブジェクトへのポインターが呼び出し先に直接渡されます。When these types require marshaling, a pointer to the object in the heap is passed to the callee directly. 呼び出し先はポインターによって参照されるメモリ位置の内容を変更できます。The callee can change the contents of the memory location being referenced by the pointer.

注意

パラメーターに Out または In/Out のマークが付いている場合、呼び出し先はメモリの内容を変更できます。逆に、In としてマーシャリングするようにパラメーターが設定されている場合、呼び出し先は内容の変更を避ける必要があります。In は書式指定された blittable 型に対する既定の設定です。The callee can change the memory contents if the parameter is marked Out or In/Out. In contrast, the callee should avoid changing the contents when the parameter is set to marshal as In, which is the default for formatted blittable types. 同じクラスをタイプ ライブラリにエクスポートし、アパートメント間呼び出しのために使用した場合に、In オブジェクトを変更すると問題が発生します。Modifying an In object generates problems when the same class is exported to a type library and used to make cross-apartment calls.

書式指定された blittable でないクラスFormatted Non-Blittable Classes

書式指定された blittable でないクラスは、固定レイアウト (書式指定されている) を持ちますが、マネージド メモリとアンマネージド メモリではデータ表現が異なります。Formatted non-blittable classes have fixed layout (formatted) but the data representation is different in managed and unmanaged memory. 次の状況では、データの変換が必要になる場合があります。The data can require transformation under the following conditions:

  • blittable でないクラスを値でマーシャリングする場合、呼び出し先はデータ構造体のコピーへのポインターを受け取ります。If a non-blittable class is marshaled by value, the callee receives a pointer to a copy of the data structure.

  • blittable でないクラスを参照でマーシャリングする場合、呼び出し先はデータ構造体のコピーへのポインターを指すポインターを受け取ります。If a non-blittable class is marshaled by reference, the callee receives a pointer to a pointer to a copy of the data structure.

  • InAttribute 属性が設定されている場合、このコピーは常にインスタンスの状態に初期化され、必要に応じてマーシャリングされます。If the InAttribute attribute is set, this copy is always initialized with the instance's state, marshaling as necessary.

  • OutAttribute 属性が設定されている場合、制御が返されるときに常に状態がインスタンスにコピーされ、必要に応じてマーシャリングされます。If the OutAttribute attribute is set, the state is always copied back to the instance on return, marshaling as necessary.

  • InAttributeOutAttribute の両方が設定されている場合は、両方のコピーが必要になります。If both InAttribute and OutAttribute are set, both copies are required. いずれか一方の属性が省略された場合、マーシャラーは一方のコピーを削除して、処理を最適化できます。If either attribute is omitted, the marshaler can optimize by eliminating either copy.

参照型Reference Types

参照型は値渡しまたは参照渡しできます。Reference types can be passed by value or by reference. 値渡しする場合は、型へのポインターがスタック上に渡されます。When they are passed by value, a pointer to the type is passed on the stack. 参照渡しする場合、型へのポインターを指すポインターがスタック上に渡されます。When passed by reference, a pointer to a pointer to the type is passed on the stack.

参照型は、次のように条件付きで動作します。Reference types have the following conditional behavior:

  • 参照型が値渡しされ、その参照型のメンバーのいずれかが非 blittable 型の場合、その型は次のように 2 回変換されます。If a reference type is passed by value and it has members of non-blittable types, the types are converted twice:

    • 引数をアンマネージ側に渡すとき。When an argument is passed to the unmanaged side.

    • 呼び出しから制御が返されるとき。On return from the call.

    不要なコピーと変換を避けるために、これらの型は In パラメーターとしてマーシャリングされます。To avoid unnecessarily copying and conversion, these types are marshaled as In parameters. 呼び出し先による変更内容を呼び出し元が確認する必要がある場合には、引数に対して明示的に InAttribute および OutAttribute 属性を適用する必要があります。You must explicitly apply the InAttribute and OutAttribute attributes to an argument for the caller to see changes made by the callee.

  • 参照型が値渡しされ、その参照型のメンバーがすべて blittable 型の場合は、マーシャリング中にその参照型を固定できます。また、呼び出し先による型のメンバーへの変更内容は呼び出し元で確認されます。If a reference type is passed by value and it has only members of blittable types, it can be pinned during marshaling and any changes made to the members of the type by the callee are seen by the caller. このような動作が必要な場合は、InAttributeOutAttribute を明示的に適用してください。Apply InAttribute and OutAttribute explicitly if you want this behavior. これらの方向属性を使用しない場合は、相互運用マーシャラーが方向情報をタイプ ライブラリにエクスポートしない (既定の In としてエクスポートする) ため、COM のアパートメント間マーシャリングで問題が生じることがあります。Without these directional attributes, the interop marshaler does not export directional information to the type library (it exports as In, which is the default) and this can cause problems with COM cross-apartment marshaling.

  • 参照型を参照渡しする場合は、既定でその型が In/Out としてマーシャリングされます。If a reference type is passed by reference, it will be marshaled as In/Out by default.

System.String と System.Text.StringBuilderSystem.String and System.Text.StringBuilder

アンマネージ コードにデータを値渡しまたは参照渡しでマーシャリングする場合、一般に、マーシャラーはデータを 2 次バッファーにコピーし (可能な場合には、コピー中に文字セットを変換)、そのバッファーへの参照を呼び出し先に渡します。When data is marshaled to unmanaged code by value or by reference, the marshaler typically copies the data to a secondary buffer (possibly converting character sets during the copy) and passes a reference to the buffer to the callee. この参照が SysAllocString によって割り当てられた BSTR である場合を除き、参照は常に CoTaskMemAlloc で割り当てられます。Unless the reference is a BSTR allocated with SysAllocString, the reference is always allocated with CoTaskMemAlloc.

いずれかの文字列型 (Unicode 文字列など) を値渡しでマーシャリングするときの最適化処理として、マーシャラーは新しいバッファーに文字列型をコピーする代わりに、呼び出し先に対して内部 Unicode バッファー内のマネージド文字列への直接ポインターを渡します。As an optimization when either string type is marshaled by value (such as a Unicode character string), the marshaler passes the callee a direct pointer to managed strings in the internal Unicode buffer instead of copying it to a new buffer.

注意事項

文字列を値渡しする場合には、マーシャラーから渡された参照を呼び出し先で変更しないようにしてください。When a string is passed by value, the callee must never alter the reference passed by the marshaler. 変更した場合はマネージド ヒープが破損することがあります。Doing so can corrupt the managed heap.

System.String を参照渡しする場合、マーシャラーは呼び出しを行う前にその文字列の内容を 2 次バッファーにコピーします。When a System.String is passed by reference, the marshaler copies the contents the string to a secondary buffer before making the call. その後、呼び出しから制御が返されるときにバッファーの内容を新しい文字列にコピーします。It then copies the contents of the buffer into a new string on return from the call. この手法により、変更不可のマネージド文字列が変更されないことが保証されます。This technique ensures that the immutable managed string remains unaltered.

System.Text.StringBuilder を値渡しする場合、マーシャラーは StringBuilder の内部バッファーへの参照を直接呼び出し元に渡します。When a System.Text.StringBuilder is passed by value, the marshaler passes a reference to the internal buffer of the StringBuilder directly to the caller. 呼び出し元と呼び出し先は、バッファーのサイズに同意する必要があります。The caller and callee must agree on the size of the buffer. 呼び出し元は、適切な長さの StringBuilder を作成します。The caller is responsible for creating a StringBuilder of adequate length. 呼び出し先は、バッファーのオーバーランが発生しないように必要な予防措置をとる必要があります。The callee must take the necessary precautions to ensure that the buffer is not overrun. StringBuilder は、値渡しされる参照型は既定で In パラメーターとして渡される、という規則の例外です。StringBuilder is an exception to the rule that reference types passed by value are passed as In parameters by default. StringBuilder は常に In/Out として渡されます。It is always passed as In/Out.

関連項目See also