删除C#不安全指针

ini*_*are 7 .net c# pointers memory-management unsafe

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

xan*_*tos 31

这取决于.你使用freedelete释放用malloc和分配的内存new.

一般来说,如果你进行PInvoke调用,那么指针应该是a IntPtr.

如果使用fixed(或GCHandle)获取托管对象的指针,则从GC内存分配内存

  • 对于GC的内存,当您取消固定该内存(退出该fixed块或释放该内存GCHandle)时,GC将返回处理它
  • 对于通过.NET Marshal方法分配的内存,您可以使用补充Free方法
  • 对于从本机方法接收的内存,您必须使用"正确"的本机方法来释放它.

固定内存的固定内存示例:

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
Run Code Online (Sandbox Code Playgroud)

或者,几乎相当(但安全性稍差,因为取消固定是手动完成的)

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
Run Code Online (Sandbox Code Playgroud)

通过使用Marshal.AllocCoTaskMem(注意Marshal.AllocCoTaskMem调用CoTaskMemAllocWindows API,因此您可以使用它们Marshal.FreeCoTaskMem和Windows API CoTaskMemFree来释放它)从"本机"池(通过COM对象通常使用的分配器)分配一些内存的示例:

// 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);
Run Code Online (Sandbox Code Playgroud)

或者支持的另一个分配器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);
Run Code Online (Sandbox Code Playgroud)

假设您有一些本机代码,可以访问存储一些数据的内存:

static extern IntPtr GetSomeMemoryFromSomeWinApi();

static extern void FreeSomeMemoryFromSomeWinApi(IntPtr ptr);
Run Code Online (Sandbox Code Playgroud)

你这样使用:

IntPtr p5 = GetSomeMemoryFromSomeWinApi();

// here you have some memory received from some native API

// and here you free it
FreeSomeMemoryFromSomeWinApi(p5);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你的库必须给你一个Free方法,因为你不知道如何分配内存,但有时你的库的文档告诉你内存是通过一个特定的分配器分配的,所以你使用那种类型的deallocator像它一样释放它

Marshal.FreeCoTaskMem(p5);
Run Code Online (Sandbox Code Playgroud)

如果API是某个COM对象.

Marshal班甚至有分配器BSTR(由COM对象使用Unicode字符串.他们有自己的长度预系列吊灯)

string str = "Hello";
char *bstr = (char*)Marshal.StringToBSTR(str);

Marshal.FreeBSTR((IntPtr)bstr);
Run Code Online (Sandbox Code Playgroud)

他们有特殊处理,因为他们的"真正的"起始地址就像(bstr - 2)(他们有一个Int32长度的前缀)

关键在于分配器的数量与沙漠的沙粒和天空的星星一样多.它们中的每一个(除了标准的.NET之一,使用的那个new)都有一个相应的解除分配器.他们像丈夫和妻子一样.他们不与他人混在一起.

最后一点,如果你写混合.NET /本地C或C++代码,你就不得不暴露调用一些C/C++方法 free/delete,因为他们的free/ delete是其C不是的OS/C++库的一部分, .

  • 喜欢这个答案! (2认同)