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

Утечка памяти в .NET.

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

Я знаю два:

Пример:

// 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();

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


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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

Ответ 9

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

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

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

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

Ответ 10

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

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

Ответ 11

Для меня это было неожиданно:

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

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

Ответ 13

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

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

Ответ 14

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

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

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

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

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