Управление памятью в C #: небезопасные ключевые слова и указатели - PullRequest
33 голосов
/ 23 марта 2010

Каковы последствия (положительные / отрицательные) использования ключевого слова unsafe в C # для использования указателей? Например, что происходит с сборкой мусора, каковы приросты / потери производительности, каковы приросты / потери производительности по сравнению с ручным управлением памятью на других языках, каковы опасности, в какой ситуации действительно оправданно использовать этот язык особенность, это больше для компиляции ...?

Ответы [ 4 ]

27 голосов
/ 01 апреля 2010

Как уже упоминал Конрад, в некоторых ситуациях небезопасный доступ к памяти в C # полезен.Их не так много , но есть некоторые:

  • Манипулирование с помощью Bitmap - это почти типичный пример, когда вам нужнонекоторая дополнительная производительность, которую вы можете получить, используя unsafe.

  • Совместимость со старыми API (такими как WinAPI или собственные библиотеки C / C ++ DLL) - это еще одна область, в которой unsafe может быть весьма полезен - например, вы можете захотетьдля вызова функции, которая принимает / возвращает неуправляемый указатель.

С другой стороны, вы можете написать большинство вещей, используя Marshall class , который скрываетмногие небезопасные операции внутри вызовов методов.Это будет немного медленнее, но это вариант, если вы хотите избежать использования unsafe (или если вы используете VB.NET, у которого нет unsafe)

ПоложительныйПоследствия : Итак, основные положительные последствия существования unsafe в C # состоят в том, что вы можете легче писать некоторый код (функциональная совместимость) и более эффективно писать некоторый код (манипулируя растровым изображением или, возможно, некоторыми тяжелыми числовыми вычислениями).использование массивов - хотя я не очень уверен насчет второго).

Негативные последствия : Конечно, есть некоторая цена, которую вы должны заплатить за использование unsafe:

  • Код, не подлежащий проверке : код C #, написанный с использованием функций unsafe, становится не проверяемым, что означает, что ваш код может скомпрометировать среду выполнения втем не мение.Это не большая проблема в сценарии с полным доверием (например, неограниченное настольное приложение) - у вас просто нет всех хороших гарантий .NET CLR.Однако вы не можете запустить приложение в условиях ограниченного доступа, таких как общедоступный веб-хостинг, Silverlight или частичное доверие (например, приложение, запущенное из сети).

  • Сборщик мусора такженужно соблюдать осторожность при использовании unsafe.GC обычно разрешается перемещать объекты в управляемой куче (для сохранения дефрагментации памяти).Когда вы берете указатель на какой-либо объект, вам нужно использовать ключевое слово fixed, чтобы сообщить GC, что он не может переместить объект до тех пор, пока вы не закончите (что может повлиять на производительность сборки мусора - но, конечно, в зависимости от точногосценарий).

Полагаю, что если бы C # не должен был взаимодействовать со старым кодом, он, вероятно, не поддержал бы unsafe (и исследовательские проекты, такие как Singularity, которые пытаются создать более поддающуюся проверке операционную системуоснованный на управляемых языках определенно запрещает использовать безопасный код).Однако в реальных условиях unsafe полезен в некоторых (редких) случаях.

9 голосов
/ 23 марта 2010

Я могу привести ситуацию, в которой стоило бы использовать:

Мне нужно генерировать растровое изображение попиксельно.Drawing.Bitmap.SetPixel() слишком медленно.Поэтому я создаю свои собственные управляемые Array растровые данные и использую unsafe, чтобы получить IntPtr для Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr).

5 голосов
/ 23 марта 2010

Цитировать Professional C # 2008:

"Две основные причины использования указатели:

  1. Обратная совместимость - Несмотря на все возможности, предоставляемые .NET-время выполнения все еще возможно вызывать собственные функции Windows API и для некоторых операций это может быть Единственный способ выполнить вашу задачу. Эти функции API обычно написано на С и часто требует указатели в качестве параметров. Однако в Во многих случаях можно написать Объявление DllImport таким образом, чтобы избегает использования указателей; например, с помощью класса System.IntPtr.
  2. Производительность - В тех случаях, когда скорость максимальна Важность, указатель может обеспечить маршрут к оптимизированной производительности. если ты знать, что вы делаете, вы можете обеспечить доступ к данным или манипулировать наиболее эффективным способом. Однако следует помнить, что чаще чем нет, есть и другие области ваш код, где вы можете сделать необходимые улучшения производительности без переориентация на указатели. Попробуйте использовать профилировщик кода для поиска узких мест в вашем коде - каждый приходит с Visual Студия 2008 ".

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

И заверните последнюю цитату:

"Мы настоятельно рекомендуем не использовать указатели излишне, потому что это будет не только сложнее писать и отлаживать, но это также подведет память проверки безопасности типов, налагаемые CLR. "

2 голосов
/ 16 августа 2010

Сборка мусора неэффективна с долгоживущими объектами. Сборщик мусора .Net работает лучше всего, когда большинство объектов освобождается довольно быстро, а некоторые объекты «живут вечно». Проблема в том, что долгоживущие объекты освобождаются только во время полной сборки мусора, что влечет за собой значительное снижение производительности. По сути, долгоживущие объекты быстро переходят в поколение 2.

(Для получения дополнительной информации вы можете прочитать о сборщике мусора в .Net: http://msdn.microsoft.com/en-us/library/ms973837.aspx)

В ситуациях, когда объекты или использование памяти в целом будут долгоживущими, ручное управление памятью даст более высокую производительность, поскольку оно может быть передано в систему без необходимости полного сбора мусора.

Внедрение некоторой системы управления памятью, основанной на одном большом байтовом массиве, структурах и множестве арифметики указателей, теоретически может повысить производительность в ситуациях, когда данные будут храниться в ОЗУ в течение длительного времени.

К сожалению, я не знаю хорошего способа ручного управления памятью в .Net для объектов, которые будут долгоживущими. По сути, это означает, что приложения с долгоживущими данными в ОЗУ периодически перестают отвечать на запросы, когда запускают полную сборку мусора всей памяти.

...