Следует ли поместить Marshal.FreeHGlobal в окончательный блок, чтобы обеспечить распределение ресурсов? - PullRequest
6 голосов
/ 20 августа 2010

У меня есть следующий блок кода:

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

Если блок будет заключен в попытку, и команда FreeHGlobal будет помещена в блок finally. (В случае, если средняя команда выдает исключение).

Кажется, имеет смысл, что, в конечном счете, это предотвратит утечки памяти в этом случае, однако из примеров, которые я нашел в Интернете, наконец, не используется. Возможно, ресурсы в любом случае автоматически удаляются (даже если они неуправляемые).

Ответы [ 2 ]

13 голосов
/ 20 августа 2010

Неуправляемая память, выделенная с помощью 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 isэто чудовище, поэтому рекомендуется соблюдать осторожность.

Примечание 2. SafeHandles хорошо работают с P / Invoke и устраняют необходимость полностью обойти IntPtrs.

SafeBuffers предназначены для безопасного манипулирования неуправляемой памятью из C #поэтому, в зависимости от того, что вы делаете (выделяя неуправляемую память для использования с P / Invoke или манипулируя неуправляемой памятью из C #), вы должны выбрать SafeHandle или SafeBuffer в качестве базового класса соответственно.

2 голосов
/ 20 августа 2010

Абсолютно. никогда не освобождается автоматически, это неуправляемая память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...