删除 C# 不安全指针 [英] Deleting C# Unsafe Pointers

查看:46
本文介绍了删除 C# 不安全指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know using the /unsafe flag in C#, you can use pointers. In C/C++ to delete a pointer you would use free(pointer); and delete pointer; respectively. However, how would you achieve the same effect with the C# pointers?

推荐答案

视情况而定.您使用 freedelete 来释放由 mallocnew 分配的内存.

It depends. You use free and delete to free memory allocated with malloc and new.

但是

通常,如果您执行 PInvoke 调用,则指针应为 IntPtr.

in general if you do a PInvoke call, then the pointer should be a IntPtr.

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

if you use fixed (or GCHandle) to obtain a pointer for a managed object, then the memory was allocated from the GC memory

  • 对于GC的内存,当你un-pin那个内存(退出fixed块,或者释放GCHandle),GC会返回处理它
  • 对于通过 .NET Marshal 方法分配的内存,您使用互补的 Free 方法
  • 对于从本机方法接收的内存,您必须使用正确"的本机方法来释放它.
  • For the memory of GC, when you un-pin that memory (exit the fixed block, or release the GCHandle), the GC will return handling it
  • For memory allocated through .NET Marshal methods you use the complementary Free method
  • For memory received from native methods, you have to use the "correct" native method to free it.

.NET 接收到的固定内存示例:

Example of pinning memory received by the .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

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

or, nearly equivalent (but a little less safe, because the unpinning is done manually)

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 来释放它):

Example of allocating some memory from the "native" pool (through the allocator normally used by COM objects) by using Marshal.AllocCoTaskMem (note that Marshal.AllocCoTaskMem calls the CoTaskMemAlloc of Windows API, so you can use both Marshal.FreeCoTaskMem and the Windows API CoTaskMemFree to free it):

// 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 通常使用的分配器):

or with another allocator supported by Marshal (this is the one normally used by 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);

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

Let's say you have some Native code that gives you access to some memory where it saves some data:

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 方法,因为你不知道内存是如何分配的,但有时你的库的文档会告诉你内存是通过一个特定的分配器,所以你使用这种类型的释放器来释放它,比如

In this case it's your library that has to give you a Free method, because you don't know how the memory was allocated, but sometimes your library's documentation tells you that the memory is allocated through a specific allocator, so you use that type of deallocator to free it, like

Marshal.FreeCoTaskMem(p5);

如果 API 是某个 COM 对象.

if the API was some COM object.

Marshal 类甚至有 BSTR 的分配器(COM 对象使用的 Unicode 字符串.它们的长度在前面)

The Marshal class even has the allocator for BSTR (Unicode strings used by COM objects. They have their length pre-pendend)

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

Marshal.FreeBSTR((IntPtr)bstr);

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

They have special handling because their "real" start address is like (bstr - 2) (they had an Int32 prepended with their length)

重点是分配器的数量和沙漠的一粒沙子和天上的星星一样多.它们中的每一个(除了标准的 .NET,new 使用的那个)都有一个对应的解除分配器.他们就像夫妻一样.他们不与其他人混在一起.

The point is that there are as many allocators as the grain of sand of the desert and the stars of the sky. Every one of them (with the exception of the standard one of .NET, the one used by new) has a corresponding deallocator. They go like husband and wife. They don't mix with others.

最后一点,如果您编写混合的 .NET/本机 C 或 C++ 代码,则必须公开一些调用他们的 free 的 C/C++ 方法/delete,因为他们的 free/delete 是他们的 C/C++ 库的一部分,而不是操作系统的一部分.

As a final note, if you write mixed .NET/native C or C++ code, you'll have to expose some C/C++ methods that call their free/delete, because their free/delete are part of their C/C++ libraries, not of the OS.

这篇关于删除 C# 不安全指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆