Подтвердить что ты не робот

Управление памятью С#: небезопасное ключевое слово и указатели

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

Ответ 2

Я могу дать вам ситуацию, когда стоит использовать:

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

Ответ 3

Процитировать Professional С# 2008:

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

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

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

И завершите его последней цитатой:

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

Ответ 4

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

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

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

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

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