GC может перемещать ссылки;использование unsafe удерживает объект вне контроля GC и избегает этого.«Фиксированный» закрепляет объект, но позволяет ГХ управлять памятью.
По определению, если у вас есть указатель на адрес объекта, и ГХ перемещает его, ваш указатель больше не действителен.
Относительно того, почему вам нужны указатели: Основная причина заключается в работе с неуправляемыми DLL, например, написанными на C ++
Также обратите внимание, что когда вы закрепляете переменные и используете указатели, вы более подвержены кучифрагментация.
Редактировать
Вы затронули основную проблему управляемого и неуправляемого кода ... как освобождается память?
Вы можете смешивать код для повышения производительности какВы описываете, что вы просто не можете пересекать управляемые / неуправляемые границы с помощью указателей (то есть вы не можете использовать указатели вне контекста «небезопасного»).
Что касается того, как они очищаются ... Вы должны управлять своей собственной памятью;объекты, на которые указывают ваши указатели, были созданы / размещены (обычно в C ++ DLL) с использованием (надеюсь) CoTaskMemAlloc()
, и вы должны освободить эту память таким же образом, вызвав CoTaskMemFree()
, иначе у вас будет утечка памяти,Обратите внимание, что с помощью CoTaskMemFree()
может быть освобождена только память, выделенная с помощью CoTaskMemAlloc()
. Другая альтернатива - предоставить метод из вашей родной библиотеки C ++, который берет указатель и освобождает его ... это позволяет DLLрешить, как освободить память, что лучше всего работает, если для выделения памяти использовался какой-то другой метод.Большинство нативных dll, с которыми вы работаете, это сторонние dll, которые вы не можете изменить, и они обычно не имеют (как я видел) таких функций для вызова.
Пример освобождения памяти, взятыйот здесь :
string[] array = new string[2];
array[0] = "hello";
array[1] = "world";
IntPtr ptr = test(array);
string result = Marshal.PtrToStringAuto(ptr);
Marshal.FreeCoTaskMem(ptr);
System.Console.WriteLine(result);
Еще несколько материалов для чтения:
C # освобождает память, на которую ссылается IntPtr Во втором ответе объясняются различные методы выделения / освобождения
Как освободить IntPtr в C #? Укрепляет необходимость освобождения таким же образом, как было выделено памяти.
http://msdn.microsoft.com/en-us/library/aa366533%28VS.85%29.aspx Официальная документация MSDN о различных способах выделения и освобождения памяти.
Короче говоря... вам нужно знать, как была выделена память, чтобы освободить ее.
Редактировать Если я правильно понимаю ваш вопрос, краткий ответ - да, вы можете передавать данные неуправляемым указателям, работать с ними в небезопасном контексте и получать данные после выхода из небезопасного контекста.
Ключ в том, что вы должны закрепить управляемый объект, на который вы ссылаетесь, блоком fixed
.Это предотвращает перемещение памяти, на которую вы ссылаетесь, GC, находясь в блоке unsafe
.Здесь есть целый ряд тонкостей, например, вы не можете переназначить указатель, инициализированный в фиксированном блоке ... вы должны прочитать небезопасные и фиксированные операторы, если вы действительно настроены на управление собственным кодом.
Все это говорит о том, что преимущества управления собственными объектами и использования указателей в том виде, в котором вы их описываете, могут не принести вам столько прироста производительности, как вы думаете.Почему нет:
- C # очень оптимизирован и очень быстр
- Ваш код указателя все еще генерируется как IL, который должен быть дополнен (после чего вступают в силу дальнейшие оптимизации)
- Вы не выключаете сборщик мусора ... вы просто скрываете объекты, с которыми работаете, от компетенции GC.Таким образом, каждые 100 мс или около того GC все еще прерывает ваш код и выполняет свои функции для всех других переменных в вашем управляемом коде.
HTH,Джеймс