我知道在C#中使用/unsafe
标记可以使用指针。在C/C++中,要删除指针,你需要分别使用free(pointer);
和delete pointer;
。然而,如何在C#中实现相同的效果呢?
我知道在C#中使用/unsafe
标记可以使用指针。在C/C++中,要删除指针,你需要分别使用free(pointer);
和delete pointer;
。然而,如何在C#中实现相同的效果呢?
free
和delete
来释放通过malloc
和new
分配的内存。
但是
一般来说,如果你进行PInvoke调用,则指针应该是一个IntPtr
。
如果你使用fixed
(或GCHandle
)获取托管对象的指针,则该内存是从GC内存中分配的。
fixed
块或释放GCHandle
)时,GC将返回处理它Marshal
方法分配的内存,需要使用相应的Free
方法以下是通过.NET接收固定内存的示例:
int[] arr = new int[5];
fixed (int* p = arr)
{
// here arr is fixed in place and it won't be freed/moved by gc
}
// here arr is un-fixed and the GC will manage it
GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned);
int* p2 = (int*)handle.AddrOfPinnedObject();
// here arr is fixed in place and it won't be freed/moved by gc
handle.Free();
// here arr is un-fixed and the GC will manage it
使用Marshal.AllocCoTaskMem
从“本地”池中分配一些内存(通过COM对象通常使用的分配器),注意Marshal.AllocCoTaskMem
调用Windows API的CoTaskMemAlloc
,因此您可以使用Marshal.FreeCoTaskMem
和Windows API的CoTaskMemFree
来释放它:
// allocating space for 1000 chars
char* p3 = (char*)Marshal.AllocCoTaskMem(1000 * sizeof(char));
// here you can use p3
// and here you free it
Marshal.FreeCoTaskMem((IntPtr)p3);
Marshal
支持的另一个分配器(这通常是 Windows API 使用的分配器):// allocating space for 1000 chars
char* p4 = (char*)Marshal.AllocHGlobal(1000 * sizeof(char));
// here you can use p4
// and here you free it
Marshal.FreeHGlobal((IntPtr)p4);
static extern IntPtr GetSomeMemoryFromSomeWinApi();
static extern void FreeSomeMemoryFromSomeWinApi(IntPtr ptr);
IntPtr p5 = GetSomeMemoryFromSomeWinApi();
// here you have some memory received from some native API
// and here you free it
FreeSomeMemoryFromSomeWinApi(p5);
在这种情况下,是您的库必须提供Free
方法,因为您不知道内存是如何分配的, 但有时您的库的文档会告诉您内存是通过特定的分配器进行分配的,因此您可以使用该类型的解除分配器来释放它,例如:
Marshal.FreeCoTaskMem(p5);
Marshal
类甚至有BSTR
的分配器(COM对象使用的Unicode字符串,它们的长度被预先添加)。string str = "Hello";
char *bstr = (char*)Marshal.StringToBSTR(str);
Marshal.FreeBSTR((IntPtr)bstr);
它们有特殊处理,因为它们的“真实”起始地址类似于(bstr-2)(它们前面有一个带有长度的Int32)
问题在于,存在着像沙漠中的沙粒和天空中的星星一样多的分配器。除了.NET标准分配器(即new
使用的分配器)之外,每个分配器都有相应的解除分配器。它们就像夫妻一样,不与其他人混在一起。
最后需要注意的是,如果您编写混合的.NET/本机C或C++代码,则必须公开某些C/C++方法,以调用它们的free
/delete
,因为它们的free
/delete
是它们的C/C++库的一部分,而不是操作系统的一部分。
在 .NET 6 中有一种新的功能,可以使用 C API 分配本地内存,即使用新的 NativeMemory。使用这种新方法,您可以轻松删除已分配的内存:
using System.Runtime.InteropServices;
unsafe
{
byte* buffer = (byte*)NativeMemory.Alloc(100);
NativeMemory.Free(buffer);
}