Очищает ли C # память, выделенную для C ++? - PullRequest
9 голосов
/ 26 марта 2009

У меня есть гипотетический COM-объект со следующей подписью

void MemAlloc(ref double[] test, int membercount)

где память выделяется в C ++ с использованием new / malloc. Как только это произойдет в C # с использованием RCW, как мне убедиться, что память освобождена правильно? Я думаю, что для .NET будет трудно освободиться, учитывая, что в C ++ вам нужно знать, был ли он выделен с помощью нового / malloc / mm_malloc, прежде чем вы сможете правильно его освободить. Итак, каков подходящий способ очистки моего выделенного массива C ++? Спасибо.

Ответы [ 4 ]

8 голосов
/ 26 марта 2009

Я считаю, что вы должны использовать CoTaskMemAlloc () для памяти, которую вы хотите явно освободить от управляемой стороны. CLR позаботится об освобождении памяти, когда она больше не будет доступна. Если вы хотите освободить его явно, вы можете использовать управляемую подпрограмму Marshal.CoTaskFree ().

Обычно маршалер взаимодействия и CLR соблюдают соглашения COM для освобождения памяти; получатель отвечает за освобождение памяти. Поэтому маршалер CLR / Interop обычно позаботится об освобождении памяти, выделенной при собственном вызове, если эта память будет возвращена управляемому вызывающему.

С Управление памятью с помощью Interop Marshaler (msdn):

Маршалер взаимодействия всегда пытается освободить память, выделенную неуправляемым код. Такое поведение соответствует COM правила управления памятью, но отличается из правил, которые управляют родным C ++.

Может возникнуть путаница, если вы предвидите родное поведение C ++ (нет памяти освобождение) при использовании вызова платформы, который автоматически освобождает память для указатели. Например, вызывая следующий неуправляемый метод из C ++ DLL не освобождает автоматически объем памяти.

Среда выполнения всегда использует Метод CoTaskMemFree для освобождения памяти. Если память, с которой вы работаете, была не выделен с CoTaskMemAlloc метод, вы должны использовать IntPtr и освободить память вручную, используя соответствующий метод.

6 голосов
/ 26 марта 2009

Оберните его в объект, который реализует IDisposable и убедитесь, что оболочка C # удаляется.

Вот блог, который я написал о простом способе реализации IDisposable.

1 голос
/ 26 марта 2009

Книга .NET 2.0 Рецепты совместимости выглядит удобной. Похоже, что он согласен с тем, что Арнши сказал о CoTaskMemFree.

1 голос
/ 26 марта 2009

Я почти на 100% уверен, что CLR не освободит автоматически память, выделенную для теста (если бы это был PInvoke, я был бы уверен на 100%) Причина в том, как CLR узнает, что вы использовали для выделения памяти в первую очередь? А именно это не так.

Более безопасный способ написания этой функции заключается в следующем

void MemAlloc(ref IntPtr arrayPtr, int membercount)

Как только вы перезвоните, вы можете сделать следующее.

var count = GetTheCount();
var arrayPtr = IntPtr.Zero;
obj.MemAlloc(ref arrayPtr, count);
byte[] test = MarshalThePtrToByteArray(arrayPtr, count);
Marshal.FreeCoTaskMem(arrayPtr);

Вот быстрая и грязная реализация MarashalThePtrToByteArray

byte[] MarashalThePtrToByteArray(IntPtr ptr, int count) {
  byte[] arr = new byte[count];
  for ( int i = 0; i < count; i++ ) {
    arr[i] = (byte)Marshal.PtrToStructure(ptr, typeof(byte));
    ptr = new IntPtr(IntPtr.ToInt64() + Marshal.SizeOf(typeof(byte)));
  }
  return arr;
}
...