只是想了解这是否有意义以及其中的意义在哪里。Marshal.AllocHGlobal(int cb)
在非托管内存中分配指定数量的字节。
但是为什么 Marshal.AllocHGlobal(0)
实际上返回一个不是 IntPtr
的 IntPtr.Zero
呢?当我使用完 0 字节后,我是否应该释放分配的 0 字节?
我看不到这个实现背后的逻辑,有人可以解释一下吗?
最佳答案
1、为什么Marshal.AllocHGlobal
分配了0个字节不返回IntPtr.Zero
?Marshal.AllocHGlobal
从 LocalAlloc
内部调用 WinAPI 函数 WinBase.h
。
至于为什么 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;
2. 为什么分配 0 字节会返回一个(有效的)内存地址?
documentation 说明了
LocalAlloc
的返回值:现在,
LocalAlloc
只有在‡ uBytes
为负 时才会失败;它对正值或零值都没有问题。这意味着分配将始终成功‡并且如果您尝试分配 0 个字节,您将始终收到一个有效的指针。
‡ 还有其他失败的原因,例如内存不足。为简单起见,本解释中省略了它们。
3. 我应该释放
Marshal.AllocHGlobal(0)
分配的内存吗?LocalAlloc
的签名是这样的:DECLSPEC_ALLOCATOR HLOCAL LocalAlloc(
UINT uFlags,
SIZE_T uBytes
);
documentation 指出出于某种原因,
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
),因为每次调用都会分配一个新的内存对象。关于c# - Marshal.AllocHGlobal(0) - 为什么这不返回 IntPtr.Zero,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52073336/