Удалить память, выделенную в C# в коде C ++ - PullRequest
0 голосов
/ 25 января 2020

У меня есть коды взаимодействия между C# (ядро) и C ++ (неуправляемая DLL).

Память, выделенная в C# с использованием Marshal.AllocHGlobal(), должна быть освобождена в C# с использованием Marshal.FreeHGlobal().

Память, выделенная в C ++ с использованием new, должна быть освобождена в C ++ с использованием delete.

Могу ли я просто delete или FreeHGlobal() всякий раз, когда я sh, так как G C больше не отслеживает эти обработчики памяти?

1 Ответ

5 голосов
/ 25 января 2020

Нет, вы не можете просто использовать любой метод, который хотите освободить память. Вы ДОЛЖНЫ использовать все, что требует от вас распределитель . Только диспетчер памяти, который выделяет данный блок памяти, знает, как правильно освободить этот блок памяти.

Например, документация для Marshal.AllocHGlobal() гласит:

Этот метод предоставляет функцию Win32 LocalAllo c из Kernel32.dll .

Когда AllocHGlobal вызывает LocalAllo c, он передает флаг LMEM_FIXED , что приводит к блокировке выделенной памяти на месте. Кроме того, выделенная память не заполнена нулями.

И документация для LocalAlloc() гласит:

Чтобы освободить памяти, используйте функцию LocalFree . Не безопасно освобождать память, выделенную с помощью LocalAllo c с использованием GlobalFree.

Вот что Marshal.FreeHGlobal() использует:

FreeHGlobal предоставляет функцию LocalFree из Kernel32.DLL , которая освобождает все байты, так что вы больше не можете использовать память, на которую указывает hglobal.

Итак, это разрешено для C# код для выделения памяти, используя Marshal.AllocHGlobal(), а затем код C ++ для освобождения этой памяти, используя LocalFree(). И наоборот, для кода C ++ для выделения памяти с использованием LocalAlloc(LMEM_FIXED), а затем для C# кода для освобождения этой памяти с использованием Marshal.FreeHGlobal().

Аналогично, класс Marshal также имеет Marshal.AllocCoTaskMem() метод:

Этот метод предоставляет функцию COM CoTaskMemAllo c , которая называется распределителем памяти задач COM.

Память, выделенная с помощью CoTaskMemAlloc(), освобождается с помощью CoTaskMemFree():

Освобождает блок памяти задач, ранее выделенный посредством вызова CoTaskMemAllo c или CoTaskMemReallo c функция.

Что и используется Marshal.FreeCoTaskMem():

FreeCoTaskMem предоставляет COM CoTaskMemFree функция , которая освобождает все байты, так что вы больше не можете использовать память, на которую указывает параметр ptr.

Итак, для кода C# разрешено выделять память с использованием Marshal.AllocCoTaskMem() а затем для кода C ++ освободить эту память, используя CoTaskMemFree(). И наоборот, для кода C ++ для выделения памяти с использованием CoTaskMemAlloc(), а затем для кода C# для освобождения этой памяти с использованием Marshal.FreeCoTaskMem().

Теперь, как говорится, менеджер памяти, который C ++ использует для своих new и delete операторов определяются реализацией . Нет никакой гарантии (или вероятности), что new использует LocalAlloc() или CoTaskMemAlloc(), или что delete использует LocalFree() или CoTaskMemFree().

Таким образом, это недопустимо для C# для освобождения любой памяти, выделенной с помощью new, или для C ++ до delete любой памяти, выделенной с помощью C#.

...