2009-12-11 4 views
22

Iは、以下の構造体を有する:Marshal.AllocHGlobal VS Marshal.AllocCoTaskMem、Marshal.SizeOf VSはsizeof()

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct WAVEHDR 
{ 
    internal IntPtr lpData; // pointer to locked data buffer 
    internal uint dwBufferLength; // length of data buffer 
    internal uint dwBytesRecorded; // used for input only 
    internal IntPtr dwUser; // for client's use 
    internal uint dwFlags; // assorted flags (see defines) 
    internal uint dwLoops; // loop control counter 
    internal IntPtr lpNext; // reserved for driver 
    internal IntPtr reserved; // reserved for driver 
} 

をIは、上記構造体のインスタンスを格納するアンマネージメモリを割り当てる必要があります。この構造体へのポインタは、waveOutのwin32 API関数(waveOutPrepareHeader、waveOutWrite、waveOutUnprepareHeader)に渡されます。

  1. Marshal.AllocHGlobal()またはMarshal.AllocCoTaskMem()を使用しますか?違いはなんですか?
  2. sizeof(WAVEHDR)またはMarshal.SizeOf(typeof(WAVEHDR))をメモリ割り当て方法に渡す必要がありますか?違いはなんですか?

割り当てられたメモリは固定する必要があります。

答えて

38

Windowsプログラムには、常にアンマネージメモリが割り当てられる少なくとも2つのヒープがあります。最初は、プログラムに代わってメモリを割り当てる必要があるときにWindowsによって使用されるデフォルトのプロセスヒープです。 2番目は、COMインフラストラクチャが割り当てに使用するヒープです。 .NET P/Invokeマーシャラは、このヒープが、関数の署名がメモリの割り当てを解除する必要があるアンマネージコードによって使用されたものと想定しています。

AllocHGlobalはプロセスヒープから割り当て、AllocCoTaskMemはCOMヒープから割り当てます。

アンマネージドinteropコードを記述するときはいつも、アンマネージメモリを割り当てるコードとそれを解放するコードが同じではない状況を回避する必要があります。間違ったデロケータが使用される可能性があります。これは特に、C/C++プログラムと相互作用するすべてのコードに当てはまります。このようなプログラムには、起動時にCRTによって作成された独自のヒープを使用する独自のアロケータがあります。他のコードでそのようなメモリを割り当て解除することは不可能です。ヒープハンドルを確実に取得することはできません。 XPやそれ以前のHeapFree()関数が、適切なヒープに割り当てられていないメモリを解放する(割り当てられたメモリをリークする)要求を黙って無視するために、VistaとWin7がクラッシュするため、これはP/Invokeのトラブルの非常に一般的な原因です。例外を伴うプログラム。

この場合、心配する必要はありません。使用しているmmsystem API関数はきれいです。それらは、割り当て解除を割り当てる同じコードを保証するように設計されています。これはwaveInPrepareHeader()を呼び出さなければならない理由の1つで、最終的にそれらを解放する同じコードでバッファを割り当てます。おそらく、デフォルトのプロセスヒープを使用しています。

WAVEHDR構造体のみを割り当てる必要があります。そして、あなたはそれを完了したときにそれをリリースする責任があります。 mmsystem APIは信頼性の高いものではありません。したがって、どちらのアロケータを使用しても、対応する空きメソッドを確実に呼び出す必要があります。すべてのWindows APIはこのように動作します。私はCoTaskMemAlloc()を使用しますが、本当に優先順位はありません。ちょうど私が間違って設計されたコードを呼んでいるなら、COMヒープを使用するのはやや難しいかもしれません。

interopシナリオでsizeof()を使用しないでください。値型の管理サイズを返します。これは、P/Invokeマーシャラが[StructLayout]および[MarshalAs]ディレクティブに従って構造タイプを変換した後は、同じではない可能性があります。 Marshal.SizeOf()のみが保証された正しい値を返します。


更新:VS2012に大きな変更がありました。これに含まれるCランタイムライブラリは、独自のヒープを使用する代わりに、デフォルトのプロセスヒープから割り当てます。長期的に、それはAllocHGlobalを成功の最も可能な道にします。

+1

2つの割り当て関数の間にパフォーマンスの違いはありますか? – DxCK

+3

'AllocCoTaskMem'がより効果的です。 'AllocHGlobal'は' LocalAlloc'を呼び出します。これは、「ローカル関数はオーバーヘッドが大きく、他のメモリ管理関数よりも少ない機能しか提供しません」というメモがあります。 https://msdn.microsoft.com/en-us/library/windows/desktop/aa366723(v=vs.85).aspxを参照してください。 – IamIC

2

1)Marshal.AllocHGlobalが確実に機能します。 Marshal.AllocCoTaskMemのドキュメントに基づいて、Marshal.AllocCoTaskMemも動作するはずです。

2)Marshal.SizeOf(typeof(WAVEHDR))を使用します。 Although you can use the Marshal.SizeOf method, the value returned by this method is not always the same as the value returned by sizeof. Marshal.SizeOf returns the size after the type has been marshaled, whereas sizeof returns the size as it has been allocated by the common language runtime, including any padding.

1

2)私がsizeofのみコンパイル時で事前定義されたサイズを有するタイプで使用することができる知っている限り。

Marshal.SizeOf(typeof(WAVEHDR))を使用してください。

関連する問題