8

次のコードブロックがあります。

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
Marshal.FreeHGlobal(unmanagedPointer);

ブロックを try でラップし、FreeHGlobal コマンドを finally ブロックに配置する必要があります。(中間コマンドが例外をスローした場合)。

この場合、最終的にメモリリークを防ぐのは理にかなっているようですが、オンラインで見つけた例から、最終的には使用されていません。いずれにせよ、リソースは自動的に破棄される可能性があります (管理されていない場合でも)。

4

2 に答える 2

15

Marshal.AllocHGlobal で割り当てられたアンマネージ メモリは、自動的に解放されません。

したがって、 Marshal.FreeHGlobal をブロックに入れることfinallyは、確かに良い考えです:

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
try
{
    Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
    SomeCommandThatCanThrowAnException();
}
finally
{
    Marshal.FreeHGlobal(unmanagedPointer);
}

あなたが見つけた例では、簡潔にするためにおそらくエラー処理を省略しています。


長期的な目的でアンマネージ メモリを割り当てる場合 (つまり、同じメソッド内で解放しない場合)、SafeHandleから派生したオブジェクト ( SafeBufferなど) でポインタをラップすることに関心があるかもしれません。

SafeHandleは IDisposable パターンを実装しているため、オブジェクトを破棄するとき、またはガベージ コレクターがオブジェクトを収集するときに、アンマネージ メモリが解放されます。SafeHandle は CriticalFinalizerObject クラスからも派生します。つまり、CLR から特別な処理を受けて、メモリが実際に解放されるようにします。

class HGlobal : SafeBuffer
{
    public HGlobal(int cb)
        : base(true)
    {
        this.SetHandle(Marshal.AllocHGlobal(cb));
        this.Initialize((ulong)cb);
    }

    protected override bool ReleaseHandle()
    {
        Marshal.FreeHGlobal(this.handle);
        return true;
    }
}

例:

using (var h = new HGlobal(buffer.Length))
{
    h.WriteArray(0, buffer, 0, buffer.Length);
}

注: SafeBuffer は非常に強力なため、注意が必要です。

注 2: SafeHandles は P/Invoke とうまく連携し、IntPtrs を完全に渡す必要がなくなります。

SafeBuffers は、C# からアンマネージ メモリを安全に操作するためのものであるため、何を行っているか (P/Invoke で使用するためにアンマネージ メモリを割り当てるか、C# からアンマネージ メモリを操作するか) に応じて、基本クラスとして SafeHandle または SafeBuffer を適切に選択する必要があります。

于 2010-08-19T20:38:55.657 に答える
2

絶対。自動的に解放されることはありません。これは管理されていないメモリです。

于 2010-08-19T20:39:03.340 に答える