Утечки памяти в .NET [закрыто]

Каковы все возможные способы утечки памяти в .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 не осталось ссылки на объект, это будет сборщик мусора через некоторое время. Так что это не способ вызвать утечки памяти.

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

Итак, каковы различные возможные пути утечки памяти?

21.08.2008 16:11:34
Как сказал Кит, ваш образец не вызывает утечек памяти.
tobsen 24.03.2010 16:32:23
14 ОТВЕТОВ
РЕШЕНИЕ

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

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

5
1.08.2010 10:50:32
Что это значит?
Eric Nicholson 13.10.2009 12:09:22
Финализатор однопоточный. «Завершение» - это то, что происходит, когда объект, который может быть удален, наконец, удаляется. Если какой-то конкретный элемент не может быть утилизирован, то ничего не удаляется, и у вас заканчивается память.
Leon Bambrick 6.11.2009 11:58:19
так что же тогда подразумевается под «блоком» в контексте - переопределить и обернуть код функцией финализатора или полностью запретить ее выполнение?
Hardryv 27.07.2010 18:17:03
Да, так как это помечено как ответ, пожалуйста, уточните с полными предложениями и т. Д.
Kieren Johnstone 27.07.2010 18:27:59
Я считаю, что он просто подразумевает использование кода в финализаторе, который никогда не завершится - либо бесконечный цикл, либо тупик, либо подобное
Basic 13.12.2010 18:09:58

Там нет никакого способа предоставить полный список ... это очень похоже на вопрос "Как вы можете промокнуть?"

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

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

14
27.07.2010 18:28:39
Как бы вы настроили FxCop для обеспечения соблюдения этого правила?
Joel 3.10.2014 15:01:34

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

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

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

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

2
3.07.2012 14:51:51

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

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

0
21.08.2008 16:18:28

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

2
21.08.2008 16:19:17
Ни за что. Разработайте на Compact Framework в .Net, и вы быстро обнаружите, что ваше устройство спешно выходит из памяти, если вы не распорядитесь своими объектами должным образом, поэтому вам не следует обобщать здесь. Вы не можете ждать GC, чтобы сделать это.
Mat Nadrofsky 12.12.2008 12:25:24

Это на самом деле не вызывает утечек, это просто делает больше работы для 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, - это большая часть того, что означает управляемый.

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

21
28.07.2010 13:10:38
@Keith Последний, к сожалению, не сработает (поскольку операции добавления и удаления обычно не находятся в одном месте - я показал это только для демонстрации проблемы). Кроме того, это не только замедляет сборщик мусора, в зависимости от сложности формы, вы можете довольно легко завершить работу приложения.
Vaibhav 21.08.2008 16:25:45
Очень опасно оставлять контроли валяться. Это нормально для небольших одноразовых приложений, но вы всегда должны размещать их в реальных приложениях, иначе вы пожалеете об этом. Поверь мне, я был там.
Niki 25.06.2010 20:24:24
Я пришел за этим, это опасная вещь - оставить одноразовые вещи вокруг! Чтобы проверить это, создайте и поместите System.Drawing.Bitmap в цикл - очень скоро вы получите OutOfMemoryException, и GC не поможет.
bohdan_trotsenko 9.12.2011 09:44:27
@modosansreves - да, это, безусловно, сломает ваше приложение. Тем не менее, потому что вы получаете управляемый, OutOfMemoryExceptionвы зависаете только это приложение. Неуправляемая утечка памяти приведет к BSOD, зависанию или другим сбоям всей машины.
Keith 12.12.2011 12:38:05

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

4
21.08.2008 16:38:56

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

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

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

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

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

0
25.11.2008 20:08:21

Установка свойства 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 пытается выдать его за законный, хорошо продуманный класс, но я думаю, что они просто создали его, чтобы устранить фундаментальную утечку в отношении управляющих валютами и привязки данных к элементам управления сеткой.

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

14
25.11.2008 20:34:06
Злой пост. У нас есть мобильное приложение, которое мы старательно очищаем, и заботимся о том, чтобы все, что реализует IDisposable, было заботливо. Даже после всего этого у нас все еще был странный сбой в поле после интенсивного использования .. У нас был именно такой сценарий! Ты жжешь.
Mat Nadrofsky 12.12.2008 12:47:43
lol +1 за комментарий Мата Надрофски
Drevak 1.12.2009 16:57:49
  1. Хранить ссылки на объекты, которые вам больше не нужны.

Другие комментарии - один из способов обеспечить вызов Dispose - это использовать использование ... когда структура кода позволяет это делать.

1
13.11.2009 01:20:48

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

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

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

Вот небольшая статья о советах по предотвращению утечек памяти .

2
27.07.2010 18:10:45

Одна вещь, которая была действительно неожиданной для меня, это:

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

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

1
25.06.2010 20:30:16

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

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

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

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

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

3
27.07.2010 18:25:47

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

1
28.07.2010 13:46:03