GC може переміщувати посилання; використання небезпечного утримує об’єкт поза контролем GC і уникає цього. "Виправлено" закріплює об'єкт, але дозволяє GC керувати пам'яттю.
За визначенням, якщо у вас є вказівник на адресу об’єкта, а GC переміщує його, ваш вказівник більше не дійсний.
Що стосується того, навіщо потрібні вказівники: Основна причина - це робота з некерованими бібліотеками DLL, наприклад, написаними на C ++
Також зауважте, коли ви закріплюєте змінні та використовуєте покажчики, ви більш сприйнятливі до фрагментації купи.
Редагувати
Ви торкнулися основної проблеми керованого та некерованого коду ... як звільняється пам’ять?
Ви можете змішувати код для продуктивності, як ви описуєте, ви просто не можете переходити керовані / некеровані межі за допомогою покажчиків (тобто ви не можете використовувати покажчики поза контекстом "небезпеки").
Що стосується того, як вони чистяться ... Ви повинні керувати власною пам’яттю; Об'єкти, на які вказують ваші вказівники, були створені / розподілені (як правило, всередині DLL C ++) за допомогою (сподіваємось) CoTaskMemAlloc()
, і вам доведеться звільнити цю пам'ять таким же чином, викликаючи CoTaskMemFree()
, інакше у вас буде витік пам'яті. Зверніть увагу, що тільки пам'ять, виділену з, CoTaskMemAlloc()
можна звільнити за допомогою CoTaskMemFree()
.
Інша альтернатива - виставити метод з вашої рідної DLL 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,
Джеймс