Marshal.AllocHGlobal VS Marshal.AllocCoTaskMem,Marshal.SizeOf VS sizeof()

DxC*_*xCK 23 .net c# winapi memory-management unmanaged

我有以下结构:

[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
}
Run Code Online (Sandbox Code Playgroud)

我需要分配非托管内存来存储上面结构的实例.指向此结构的指针将传递给waveOut win32 api函数(waveOutPrepareHeader,waveOutWrite,waveOutUnprepareHeader).

  1. 我应该使用Marshal.AllocHGlobal()Marshal.AllocCoTaskMem()?有什么不同?
  2. 我应该通过sizeof(WAVEHDR)还是Marshal.SizeOf(typeof(WAVEHDR))内存分配方法?有什么不同?

注意必须固定分配的内存.

Han*_*ant 43

Windows程序始终至少有两个堆,其中分配了非托管内存.首先是Windows在需要代表程序分配内存时使用的默认进程堆.第二个是COM基础结构用于分配的堆..NET P/Invoke marshaller假定任何非托管代码使用此堆,其功能签名需要取消分配内存.

AllocHGlobal从进程堆分配,AllocCoTaskMem从COM堆分配.

无论何时编写非托管互操作代码,都应该始终避免分配非托管内存的代码与释放它的代码不同的情况.使用错误的解除分配器的可能性很大.对于使用C/C++程序进行交互的任何代码尤其如此.这些程序有自己的分配器,它使用自己的堆,由CRT在启动时创建.在其他代码中取消分配这样的内存是不可能的,你无法可靠地获得堆处理.这是P/Invoke问题的一个非常常见的原因,特别是因为XP和更早版本中的HeapFree()函数无声地忽略了释放未在正确堆中分配的内存的请求(泄漏分配的内存)但Vista和Win7崩溃了程序有例外.

在您的情况下无需担心这一点,您使用的mmsystem API函数是干净的.它们旨在确保分配也释放的相同代码.这是你必须调用waveInPrepareHeader()的一个原因,它使用相同的代码分配缓冲区,最终解除分配它们.可能与默认进程堆.

您只需要分配WAVEHDR结构.当你完成它时,你有责任释放它.mmsystem API不适合你,最重要的是因为它们无法可靠地执行此操作.因此,您可以使用任一分配器,您只需要确保调用相应的自由方法.所有Windows API都以这种方式工作.我使用CoTaskMemAlloc(),但确实没有偏好.只是如果我调用设计错误的代码,使用COM堆稍微有点可能.

您绝不应在互操作方案中使用sizeof().它返回值类型的托管大小.在P/Invoke marshaller根据[StructLayout]和[MarshalAs]指令转换结构类型之后,这可能不一样.只有Marshal.SizeOf()为您提供有保证的正确值.


更新:VS2012发生了很大的变化.它包含的C运行时库现在从默认进程堆分配,而不是使用自己的堆.从长远来看,这使得AllocHGlobal成为最有可能取得成功的途径.

  • `AllocCoTaskMem`更高效.`AllocHGlobal`调用`LocalAlloc`,它有以下注释:"本地函数具有更大的开销,并提供比其他内存管理函数更少的功能." 请参阅https://msdn.microsoft.com/en-us/library/windows/desktop/aa366723(v=vs.85).aspx (3认同)