C# でフラグを使用することは知ってい/unsafe
ますが、ポインターを使用できます。C/C++ でポインターを削除するには、それぞれ と を使用free(pointer);
しdelete pointer;
ます。しかし、C# ポインターを使用して同じ効果を得るにはどうすればよいでしょうか?
2 に答える
場合によります。と で割り当てられたメモリを解放するにはfree
、 とを使用します。delete
malloc
new
しかし
一般に、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.AllocCoTaskMem
をMarshal.AllocCoTaskMem
呼び出すので、と Windows API のCoTaskMemAlloc
両方を使用してメモリを解放できます):Marshal.FreeCoTaskMem
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);
データを保存するメモリにアクセスできるネイティブ コードがあるとします。
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
ためです。 .free
delete
.NET 6 には、C API を使用してネイティブ メモリを割り当てる新しい機能があり、それは新しい NativeMemory を使用しています。この新しいメソッドを使用すると、割り当てられたメモリを簡単に削除できます (削除する必要があります)。
using System.Runtime.InteropServices;
unsafe
{
byte* buffer = (byte*)NativeMemory.Alloc(100);
NativeMemory.Free(buffer);
}