我知道在 C# 中使用 /unsafe
标志,您可以使用指针。在 C/C++ 中,要删除指针,您可以分别使用 free(pointer);
和 delete pointer;
。但是,如何使用 C# 指针实现相同的效果?
最佳答案
这取决于。您使用 free
和 delete
来释放使用 malloc
和 new
分配的内存。
但是
一般来说,如果您执行 PInvoke 调用,那么指针应该是 IntPtr
。
如果您使用fixed
(或GCHandle
)获取托管对象的指针,那么该内存是从GC内存中分配的
- 对于GC的内存,当你un-pin那 block 内存时(退出
fixed
block ,或者释放GCHandle
),GC会返回处理它< - 对于通过 .NET
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
从“ native ”池(通过 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);
假设您有一些 native 代码,可以让您访问一些保存一些数据的内存:
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);
如果 API 是某个 COM 对象。
Marshal
类甚至有 BSTR
的分配器(COM 对象使用的 Unicode 字符串。它们的长度有前置项)
string str = "Hello";
char *bstr = (char*)Marshal.StringToBSTR(str);
Marshal.FreeBSTR((IntPtr)bstr);
它们有特殊处理,因为它们的“真实”起始地址类似于 (bstr - 2)(它们有一个 Int32
前缀)
关键是分配器的数量与沙漠中的沙粒和天空中的星星一样多。它们中的每一个(除了 .NET 的标准之一,new
使用的那个)都有一个相应的释放器。他们就像夫妻一样。他们不与其他人混在一起。
最后一点,如果您编写混合的 .NET/ native C 或 C++ 代码,则必须公开一些调用他们的 free
的 C/C++ 方法/delete
,因为他们的free
/delete
是他们的 C/C++ 库的一部分,而不是操作系统的一部分。
关于c# - 删除 C# 不安全指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18172979/