Вопрос

Каковы все возможные способы возникновения утечек памяти в .NET?

Я знаю два:

  1. Не правильно отменяю регистрацию Обработчики событий/Делегаты.
  2. Не удалять динамические дочерние элементы управления в Windows Forms:

Пример:

// Causes Leaks  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  

// Correct Code  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  
label.Dispose();

Обновлять:Идея состоит в том, чтобы перечислить распространенные ошибки, которые не слишком очевидны (например, описанные выше).Обычно считается, что утечки памяти не являются большой проблемой из-за сборщика мусора.Не так, как раньше в C++.


Отличная дискуссия, ребята, но позвольте мне уточнить...по определению, если на объект в .NET не осталось ссылки, в какой-то момент он будет собран мусором.Так что это не способ вызвать утечки памяти.

В управляемой среде я бы посчитал это утечкой памяти, если бы у вас была непреднамеренная ссылка на любой объект, о котором вы не знаете (отсюда и два примера в моем вопросе).

Итак, каковы возможные способы возникновения такой утечки памяти?

Это было полезно?

Решение

Заблокируйте поток финализатора.Никакие другие объекты не будут собирать мусор до тех пор, пока поток финализатора не будет разблокирован.Таким образом, объем используемой памяти будет расти и расти.

Дальнейшее чтение: http://dotnetdebug.net/2005/06/22/blocked-finalizer-thread/

Другие советы

На самом деле это не вызывает утечек, а просто увеличивает нагрузку на GC:

// slows GC
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  

// better  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  
label.Dispose();

// best
using( Label label = new Label() )
{ 
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
}

Оставление одноразовых компонентов в таком виде никогда не является большой проблемой в управляемой среде, такой как .Net — это большая часть того, что означает управляемость.

Вы, конечно, замедлите работу приложения.Но вы не оставите беспорядок ни для чего другого.

Установка GridControl.DataSource напрямую, без использования экземпляра класса BindingSource (http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx).

Это привело к утечкам в моем приложении, поиск которых с помощью профилировщика занял у меня немало времени. В конце концов я нашел отчет об ошибке, на который Microsoft отреагировала: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=92260

Забавно, что в документации к классу BindingSource Microsoft пытается выдать его за вполне законный и продуманный класс, но я думаю, что они просто создали его для устранения фундаментальной утечки, касающейся валютных менеджеров и привязки данных к элементам управления сеткой.

Остерегайтесь этого, я уверен, что из-за этого существует множество приложений с утечками!

Полный список предоставить невозможно...это очень похоже на вопрос: «Как можно промокнуть?»

Тем не менее, убедитесь, что вы вызываете Dispose() для всего, что реализует IDisposable, и убедитесь, что вы реализуете IDisposable для всех типов, которые потребляют неуправляемые ресурсы любого типа.

Время от времени запускайте в своей кодовой базе что-то вроде FxCop, чтобы обеспечить соблюдение этого правила — вы будете удивлены, насколько глубоко некоторые одноразовые объекты скрыты внутри среды приложения.

Исключения в методах Finalize (или Dispose из Finaliser), которые препятствуют правильному удалению неуправляемых ресурсов.Распространенная проблема из-за программатора предполагая объекты какого порядка будут удалены, и попытка освободить одноранговые объекты, которые уже были удалены, приводит к исключению, а остальная часть метода Finalise/Dispose from Finalize не вызывается.

У меня есть еще 4 пункта, которые я могу добавить к этому обсуждению:

  1. Завершение потоков (Thread.Abort()), создавших элементы управления пользовательского интерфейса, без надлежащей подготовки к такому событию может привести к ожидаемому использованию памяти.

  2. Доступ к неуправляемым ресурсам через Pinvoke без их очистки может привести к утечкам памяти.

  3. Изменение больших строковых объектов.Это не обязательно утечка памяти, если выйти за рамки, об этом позаботится GC, однако с точки зрения производительности ваша система может пострадать, если большие строки часто изменяются, потому что вы не можете действительно зависеть от GC, чтобы гарантировать, что размер вашей программы невелик. минимальный.

  4. Частое создание объектов GDI для выполнения пользовательского рисования.Если работа с GDI выполняется часто, повторно используйте один объект GDI.

Вызов IDisposable каждый раз — это самый простой способ начать и, безусловно, эффективный способ выявить все легко висящие плоды утечек памяти в кодовой базе.Однако этого не всегда достаточно.Например, также важно понимать, как и когда во время выполнения генерируется управляемый код, и что после загрузки сборок в домен приложения они никогда не выгружаются, что может увеличить объем приложения.

Чтобы предотвратить утечки памяти .NET:

1) Используйте конструкцию «using» (или конструкцию «try-finally») всякий раз, когда создается объект с интерфейсом «IDisposable».

2) Сделайте классы «IDisposable», если они создают поток или добавляют объект в статическую или долгоживущую коллекцию.Помните, что «событие» C# — это коллекция.

Вот короткая статья о Советы по предотвращению утечек памяти.

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

Другими словами, это отсылки, о которых человек, называющий их утечками памяти, не знал или забыл.

Редактировать:Или это настоящие ошибки в сборщике мусора или неуправляемом коде.

Редактировать 2:Еще один способ подумать об этом — всегда следить за тем, чтобы внешние ссылки на ваши объекты освобождались соответствующим образом.Внешний означает код, находящийся вне вашего контроля.Любой случай, когда это происходит, является случаем, когда вы можете «утечь» память.

  1. Сохранение ссылок на объекты, которые вам больше не нужны.

По поводу других комментариев: один из способов обеспечить вызов Dispose — использовать using...когда структура кода это позволяет.

Для меня было очень неожиданно следующее:

Region oldClip = graphics.Clip;
using (Region newClip = new Region(...))
{
    graphics.Clip = newClip;
    // draw something
    graphics.Clip = oldClip;
}

Где утечка памяти?Верно, тебе следовало избавиться oldClip, слишком!Потому что Graphics.Clip — одно из редких свойств, которое возвращает новый одноразовый объект каждый раз, когда вызывается геттер.

Тесс Фернандес Имеет отличные статьи в блоге о поиске и устранении утечек памяти.Лаборатория 6 Лаборатория 7

Многие вещи, которые могут вызвать утечки памяти в неуправляемых языках, все же могут вызывать утечки памяти в управляемых языках.Например, плохая политика кэширования может привести к утечкам памяти.

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

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

Зашедший в тупик поток финализатора предотвратит запуск всех оставшихся финализаторов и, таким образом, предотвратит восстановление всех финализируемых объектов (поскольку они все еще находятся в корне доступного списка).

На многопроцессорной машине вы можете создавать финализируемые объекты быстрее, чем поток финализатора может запускать финализаторы.Пока это поддерживается, у вас будет «утечка» памяти.Вероятность того, что это произойдет в дикой природе, маловероятна, но это легко воспроизвести.

Куча больших объектов не уплотняется, поэтому из-за фрагментации может возникнуть утечка памяти.

Есть ряд объектов, которые необходимо освободить вручную.Например.удаленное взаимодействие объектов без аренды и сборок (необходимо выгрузить AppDomain).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top