2008-08-21 5 views
20

Каковы все возможные способы, с помощью которых мы можем получить утечки памяти в .NET?Утечки памяти в .NET

Я знаю двух:

  1. Не правильно отмены регистрации Event Handlers/Delegates.
  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(); 

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


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

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

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

+2

Как сказал Кейт, ваш образец не вызывает утечки памяти. – tobsen 2010-03-24 16:32:23

ответ

5

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

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

14

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

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

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

+0

Как бы вы установили FxCop для принудительного применения этого правила? – Joel 2014-10-03 15:01:34

2

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

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

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

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

0

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

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

2

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

+2

Ни в коем случае. Разработайте на Compact Framework в .Net, и вы быстро узнаете, что ваше устройство быстро отрывается из памяти, если вы неправильно распоряжаетесь своими объектами, поэтому вы не должны здесь обобщать. Вы не можете дождаться, когда GC это сделает. – 2008-12-12 12:25:24

21

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

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

+1

Очень опасно оставлять элементы управления лежащими. Это нормально для небольших приложений, но вы всегда должны распоряжаться ими в реальных приложениях, или вы пожалеете об этом. Поверьте мне, я был там. – Niki 2010-06-25 20:24:24

+1

Я подошел к этому, это опасная вещь - оставив одноразовые предметы! Чтобы проверить это, создайте и отпустите System.Drawing.Bitmap в цикле - вы очень скоро получите OutOfMemoryException, и GC не поможет. – 2011-12-09 09:44:27

+1

@modosansreves - да, это наверняка разорвет ваше приложение. Однако, поскольку вы получаете управляемое «OutOfMemoryException», вы запускаете только это приложение.Неуправляемая утечка памяти будет BSOD, повесить или иначе разрушить всю машину. – Keith 2011-12-12 12:38:05

4

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

0

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

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

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

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

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

14

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

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

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

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

2

Для предотвращения утечки памяти .NET:

1) используют «», используя конструкцию (или «примерочных, наконец, построить) всякий раз, когда объект с„“IDisposable интерфейс создается.

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

Вот краткая статья о Tips to Prevent Memory Leaks.

1

Единственное, что было действительно неожиданно для меня это:

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

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

3

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

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

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

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

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

1

Tess Fernandez Имеет отличные сообщения в блогах об обнаружении и отладке утечек памяти. Lab 6Lab 7