как работает Marshal.FreeHGlobal ()? - PullRequest
1 голос
/ 09 февраля 2011

У меня есть пользовательский интерфейс на C #, который использует C ++ DLL. Моим требованием было передать большой кусок памяти из C # в DLL. DLL запишет в этот буфер памяти и передаст его обратно в C #. Я использовал IntPtr & функции глобальной памяти, чтобы сделать это. Все отлично работает.

Вопрос в том, как проверить, очистил ли Marshal.FreeHGlobal () память? Я использую большой кусок памяти, обычно в мегабайтах. Поэтому я хочу убедиться, что память очищена мгновенно.

Ответы [ 2 ]

4 голосов
/ 09 февраля 2011

Если вы передадите действительный дескриптор Marshal.FreeHGlobal, он будет освобожден.Но так как метод не возвращает значение, вы не можете точно сказать, было ли оно очищено.

Если у вас есть некоторые сомнения относительно того, передаете ли вы правильную вещь в FreeHGlobal,тогда я полагаю, что ваш код, вероятно, не так чист, как должно быть.Но если вы действительно хотите убедиться, тогда вы можете вызвать функцию LocalFree Windows API, передав ей дескриптор, который вы бы передали FreeHGlobal:

[DllImport("kernel32", SetLastError=true)]
static extern IntPtr LocalFree(IntPtr mem);

// Now, to free a block of memory allocated with Marshal.AllocHGlobal
IntPtr rslt = LocalFree(memPtr);
if (rslt == IntPtr.Zero)
{
    // success!
}
else
{
    int err = Marshal.GetLastWin32Error();
    // do something with the error.
}

Я бы предложил, однако,что если вы сделаете это, вы вызовете LocalAlloc для выделения памяти, а не вызовете Marshal.AllocHGlobal, поскольку вполне возможно (хотя, вероятно, маловероятно), что будущие версии .NET могут использовать что-то отличное от LocalAlloc для выделения неуправляемой памяти.Если это произойдет, то ваш код, который зависит от LocalFree, сломается.

0 голосов
/ 09 июля 2017

Возможно, вы также можете выделить массив в управляемой памяти, а затем создать GCHandle, чтобы разрешить доступ к нему из неуправляемой памяти.

Например, здесь я звоню PowerReadACValue; функция Win32 API получает буфер LPBYTE (что равно BYTE*).

Сначала я вызываю его с помощью «нулевого указателя» (IntPtr.Zero), чтобы он сообщал мне, какой размер буфера мне нужен (это выводится в bufferSize). Затем я выделяю буфер и передаю указатель через GCHandle s AddrOfPinnedObject.

uint type;
uint bufferSize = 0;

if (SafeNativeMethods.PowerReadACValue(IntPtr.Zero, this.m_planHandle, ref subGroupOfPowerSettingsGuid, ref powerSettingGuid, out type, IntPtr.Zero, ref bufferSize) != 0)
{
    throw new Win32Exception();
}

byte[] buffer = new byte[bufferSize];
GCHandle bufferPointer = default(GCHandle);
try
{
    bufferPointer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    if (SafeNativeMethods.PowerReadACValue(IntPtr.Zero, this.m_planHandle, ref subGroupOfPowerSettingsGuid, ref powerSettingGuid, out type, bufferPointer.AddrOfPinnedObject(), ref bufferSize) != 0)
        throw new Win32Exception();
}
finally
{
    if (bufferPointer.IsAllocated)
        bufferPointer.Free();
}

Кроме того, я мог бы выделить буфер с помощью Marshal.AllocHGlobal, который также возвращает мне IntPtr, а затем освободить его с помощью Marshal.FreeGlobal, но в этом случае мне нужно использовать данные в массиве из управляемого код. Если бы я просто собирался передать указатель массива на другую неуправляемую функцию, даже не прикасаясь к ней из управляемого кода, это был бы лучший путь (пока GCHandle активен, память блокируется в памяти, что влияет на сборщик мусора ).

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