8

C# でフラグを使用することは知ってい/unsafeますが、ポインターを使用できます。C/C++ でポインターを削除するには、それぞれ と を使用free(pointer);delete pointer;ます。しかし、C# ポインターを使用して同じ効果を得るにはどうすればよいでしょうか?

4

2 に答える 2

32

場合によります。と で割り当てられたメモリを解放するにはfree、 とを使用します。deletemallocnew

しかし

一般に、PInvoke 呼び出しを行う場合、ポインターはIntPtr.

fixed(または) を使用GCHandleして管理対象オブジェクトのポインターを取得する場合、メモリは GC メモリから割り当てられました。

  • GC のメモリについては、そのメモリのピンを外す (fixedブロックを終了する、または を解放する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

を使用して「ネイティブ」プールから (COM オブジェクトで通常使用されるアロケーターを介して) メモリを割り当てる例 (は Windows APIMarshal.AllocCoTaskMemMarshal.AllocCoTaskMem呼び出すので、と Windows API のCoTaskMemAlloc両方を使用してメモリを解放できます):Marshal.FreeCoTaskMemCoTaskMemFree

// 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);

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/ネイティブ C または C++ コードを記述する場合、/ freeを呼び出すいくつかの C/C++ メソッドを公開する必要があります。これらの/は、OS ではなく C/C++ ライブラリの一部であるdeleteためです。 .freedelete

于 2013-08-11T14:30:28.217 に答える
0

.NET 6 には、C API を使用してネイティブ メモリを割り当てる新しい機能があり、それは新しい NativeMemory を使用しています。この新しいメソッドを使用すると、割り当てられたメモリを簡単に削除できます (削除する必要があります)。

using System.Runtime.InteropServices;

unsafe
{
    byte* buffer = (byte*)NativeMemory.Alloc(100);

    NativeMemory.Free(buffer);
}
于 2021-08-24T05:17:58.530 に答える