只是试图了解这是否有意义以及意义在何处。
Marshal.AllocHGlobal(int cb)
在非托管内存中分配指定数量的字节。
但是为什么Marshal.AllocHGlobal(0)
实际上返回不是 IntPtr
的{{1}}?使用完0个字节后,我应该释放分配的0个字节吗?
我看不到此实现背后的逻辑,有人可以解释吗?
答案 0 :(得分:4)
Marshal.AllocHGlobal
不返回IntPtr.Zero
? Marshal.AllocHGlobal
从WinBase.h
内部调用WinAPI函数LocalAlloc
。
关于Marshal.AllocHGlobal(0)
不返回IntPtr.Zero
的原因:
如果分配期间失败,LocalAlloc
仅返回NULL
(等效于C#:IntPtr.Zero
)。
也可以在source code中看到:
IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes));
if (pNewMem == IntPtr.Zero) {
throw new OutOfMemoryException();
}
return pNewMem;
documentation说说LocalAlloc
的返回值:
如果函数成功,则返回值是新分配的内存对象的句柄。
如果函数失败,则返回值为
NULL
。
现在,LocalAlloc
仅在‡uBytes
为负的情况下失败;正值或零值都没有问题。
这意味着分配将始终成功‡,并且如果您尝试分配0个字节,您将始终收到有效的指针。
‡失败还有其他原因,例如内存不足。为简单起见,在此说明中将它们省略。
Marshal.AllocHGlobal(0)
分配的内存吗? LocalAlloc
的签名是这样:
DECLSPEC_ALLOCATOR HLOCAL LocalAlloc(
UINT uFlags,
SIZE_T uBytes
);
如果[{
uBytes
]为零,并且uFlags
参数指定LMEM_MOVEABLE
,则该函数将返回标记为已废弃的内存对象的句柄。
出于某种原因,Marshal.AllocHGlobal(0)
不会通过LMEM_MOVEABLE
,而是通过LMEM_FIXED
。
文档缺少有关此特定案例的信息。运行测试(如下所示)表明实际上已分配了内存,并且您绝对需要释放内存,如下所示:
IntPtr zeroBytesPtr = Marshal.AllocHGlobal(0);
// Do stuff with the pointer.
Marshal.FreeHGlobal(zeroBytesPtr);
如果Marshal.AllocHGlobal
传递了LMEM_MOVEABLE
,则无需在任何地方释放指针。
对于测试:
while(true) {
void* v = LocalAlloc(LMEM_FIXED, 0);
}
为循环的每次迭代分配内存,并且每次都返回一个新地址,而
while(true) {
void* v = LocalAlloc(LMEM_MOVEABLE, 0);
}
仅分配一次内存,并每次返回相同地址。
这表明为什么必须释放Marshal.AllocHGlobal
分配的内存(因为它使用LMEM_FIXED
),因为每次调用都会分配一个新的内存对象。
答案 1 :(得分:1)
在某些用例中,对AllocHGlobal
的两个不同调用永远不会返回 same IntPtr
值(不存在任何FreeHGlobal
调用),甚至可能很重要如果有两个调用恰好指定了一个有点废话的大小值。
最终,您可能是为了与非托管代码(希望与“全局”堆一起使用)互操作而调用此函数。长期以来,GlobalAlloc
都被接受为0
值,并且该函数实际上总是执行一些分配(如果成功的话)。