Страницы

Поиск по вопросам

вторник, 28 января 2020 г.

Управление памятью в C#

#c_sharp #производительность #memory


Подскажите, пожалуйста, возможно ли вручную управлять памятью в C#? Например удалять
объекты когда тебе это необходимо, а не когда заблагорассудится сборщику мусора.
    


Ответы

Ответ 1



Можно, но в ограниченных пределах, а вообще не нужно. Если используете классы, реализующие IDisposable, не забывайте про Dispose() (либо про конструкцию using)

Ответ 2



Я перечитал статью, на которую указывает ТС. Статья датирована 2006-м годом, с тех времён алгоритмы сборки мусора сильно изменились. Я скомпилировал и запустил проекты на тестовой 32-битной машине. (Заметьте, что на 64-битной машине гораздо больше доступного адресного пространства, и сборщик мусора будет работать гораздо меньше. У кого под рукой 64-битная машина, проверьте, пожалуйста, сравните и отпишитесь!) C++: В исходниках исправил 10000 на PermanentObjectsCount в строке 102, была явная ошибка. Скомпилировал Release, запуск с командной строки 5 раз, с разными опциями. Параметры теста: PermanentObjectsCount: количество «мёртвых» объектов, которые лишь занимают память и мешают алгоритмам аллокации QUICK_HEAP_OPERATOR_NEW: макрос, подключающий кастомный аллокатор памяти Результаты: PermanentObjectsCount = 1, QUICK_HEAP_OPERATOR_NEW включено: Timestamp: 2.332243/2.285392/2.310033/2.329071/2.362159, среднее 2,3237796 ObjCount=10001001 PermanentObjectsCount = 1, QUICK_HEAP_OPERATOR_NEW выключено Timestamp: 3.123940/3.130930/3.113295/3.139964/3.104077, среднее 3.1224412 ObjCount=10001001 PermanentObjectsCount = 10 * 1000 * 1000, QUICK_HEAP_OPERATOR_NEW включено: Timestamp: 7.175451/7.234413/7.241763/7.197331/7.226205, среднее 7.2150326 ObjCount=20001000 PermanentObjectsCount = 10 * 1000 * 1000, QUICK_HEAP_OPERATOR_NEW выключено: Timestamp: 8.823886/8.751605/8.908837/8.825099/8.806487, среднее 8.8231828 ObjCount=20001000 Теперь C#: Переконфигурировал проект на использования .NET 4.5. Скомпилировал Release, запуск с командной строки 5 раз, с разными опциями. Параметры теста: PermanentObjectsCount: количество «мёртвых» объектов, которые лишь занимают память и мешают сборщику мусора Установки сборщика мусора в app.config по умолчанию ( отключено): PermanentObjectsCount = 1 00:00:01.6406347/1.5898657/1.6479692/1.6528195/1.5796367, среднее 1.62218516 Количество созданных объектов: 10001001 Количество сборок мусора поколения 0: 571 Количество сборок мусора поколения 1: 145 Количество сборок мусора поколения 2: 3 PermanentObjectsCount = 10 * 1000 * 1000 00:00:15.5065372/16.4615645/16.5447826/15.4274263/16.3169154, среднее 16.0514452 Количество созданных объектов: 20001000 Количество сборок мусора поколения 0: 758 Количество сборок мусора поколения 1: 256 Количество сборок мусора поколения 2: 10 Запросил серверный сборщик мусора в app.config (): PermanentObjectsCount = 1 00:00:01.9130864/1.8731294/1.8649931/1.6231794/1.8787851, среднее 1.83063468 Количество созданных объектов: 10001001 Количество сборок мусора поколения 0: 243 Количество сборок мусора поколения 1: 43 Количество сборок мусора поколения 2: 3 PermanentObjectsCount = 10 * 1000 * 1000 00:00:14.2030724/13.8427775/14.0393846/14.5345637/14.2312238, среднее 14.1702044 Количество созданных объектов: 20001000 Количество сборок мусора поколения 0: 249 Количество сборок мусора поколения 1: 54 Количество сборок мусора поколения 2: 5 Выводы: Сборщик мусора тогда и сборщик мусора сейчас — разные вещи. В довольно редком для реальных программ случае наличия 10 миллионов статических объектов сборщик мусора .NET существенно ускорился, и теперь отстаёт от нативного аллокатора не в 86 раз, а всего вдвое. Серверный аллокатор немного лучше справляется с нагрузкой. В случае, когда работа управления памятью не затруднена, аллокатор .NET выигрывает более чем в полтора раза. Кастомный аллокатор для нативного кода ускоряет работу, но я бы не стал использовать непроверенный аллокатор в серьёзном коде: был бы он лучше встроенного в C++, уж разработчики компилятора без сомнений заменили бы свой аллокатор на этот.

Ответ 3



Если вы работаете с COM объектами, то им нужно вызывать метод Marshal.ReleaseComObject

Комментариев нет:

Отправить комментарий