c# - 删除 C# 不安全指针

标签 c# .net pointers memory-management unsafe

我知道在 C# 中使用 /unsafe 标志,您可以使用指针。在 C/C++ 中,要删除指针,您可以分别使用 free(pointer);delete pointer;。但是,如何使用 C# 指针实现相同的效果?

最佳答案

这取决于。您使用 freedelete 来释放使用 mallocnew 分配的内存。

但是

一般来说,如果您执行 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/

相关文章:

c - C中的单链表

c# - 从表单处理类中的自定义事件

c# - 在远程机器上运行代码

c# - 如何从 Blazor WebAssembly 中的 Razor 页面访问 body 标签或其他标签?

c# - 检查列表是否包含一个属性相同的对象的优雅方法,并且仅在另一个属性的日期较晚时才替换

c# - Windows Installer 安装进度状态消息

c# - 玩字节...需要从 Java 转换为 C#

.net - TFS 2010 工作项 - 工作项链接

c++ - 类的指针成员必须指向堆分配的数据?

c - 将加密文件中的二进制数据写入指定的内存位置