Вопрос

В перспективе .NET:

  • Что такое утечка памяти?
  • Как вы можете определить, есть ли утечка в вашем приложении?Каковы будут последствия?
  • Как вы можете предотвратить утечку памяти?
  • Если в вашем приложении произошла утечка памяти, исчезает ли она при завершении процесса или его остановке?Или утечки памяти в вашем приложении влияют на другие процессы в системе даже после завершения процесса?
  • А как насчет неуправляемого кода, доступ к которому осуществляется через COM Interop и / или P / Invoke?
Это было полезно?

Решение

Лучшее объяснение, которое я видел, содержится в главе 7 книги "Свободный Электронная книга "Основы программирования".

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

Вы узнаете, что у вас есть утечки, когда начнете получать исключения OutOfMemoryExceptions или использование вашей памяти превысит то, что вы ожидали (Совершенство имеет хорошие счетчики памяти).

Понимание .NETмодель памяти - ваш лучший способ избежать этого.В частности, для понимания того, как работает сборщик мусора и как работают ссылки — опять же, я отсылаю вас к главе 7 электронной книги.Кроме того, помните о распространенных подводных камнях, вероятно, наиболее распространенными из которых являются события.Если возражать A регистрируется событие на объекте B, затем возразить A будет оставаться здесь до тех пор, пока не возразит B исчезает, потому что B содержит ссылку на A.Решение состоит в том, чтобы отменить регистрацию ваших событий, когда вы закончите.

Конечно, хороший профиль памяти позволит вам увидеть графики ваших объектов и изучить вложенность / ссылки на ваши объекты, чтобы увидеть, откуда берутся ссылки и какой корневой объект отвечает (профиль муравьев с красными воротами, Точка памяти JetBrains, memprofiler - файл памяти это действительно хороший выбор, или вы можете использовать только текстовый WinDbg ( ветер ) и SOS, но я бы настоятельно рекомендовал коммерческий / визуальный продукт, если только вы не настоящий гуру).

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

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

Строго говоря, утечка памяти - это потребление памяти, которая "больше не используется" программой.

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

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

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

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

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

Как понять, есть ли утечка в вашем приложении

Один интересный способ - открыть совершенство и добавьте трассировки для # байты во всех кучах и Коллекции # Gen 2 , в каждом конкретном случае рассматривая только ваш процесс.Если использование определенной функции приводит к увеличению общего количества байтов, и эта память остается выделенной после следующего сбора данных поколения 2, вы можете сказать, что функция допускает утечку памяти.

Как предотвратить

Были высказаны и другие хорошие мнения.Я бы просто добавил, что, возможно, чаще всего упускается из виду причиной утечек памяти .NET является добавление обработчиков событий к объектам без их удаления.Обработчик событий, прикрепленный к объекту, является формой ссылки на этот объект, поэтому будет препятствовать сбору данных даже после удаления всех других ссылок.Всегда помните об отсоединении обработчиков событий (используя -= синтаксис в C#).

Исчезает ли утечка при завершении процесса, и как насчет COM-взаимодействия?

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

Я бы определил утечку памяти как объект, который не освобождает всю память, выделенную после его завершения.Я обнаружил, что это может произойти в вашем приложении, если вы используете Windows API и COM (т. е.неуправляемый код, в котором есть ошибка или которым неправильно управляют), во фреймворке и в компонентах сторонних производителей.Я также обнаружил, что неполадки после использования определенных объектов, таких как ручки, могут вызвать проблему.

Лично я страдал от исключений из-за нехватки памяти, которые могут быть вызваны, но не являются исключительными для утечек памяти в приложениях dot net.(ООМ также может быть получен из закрепления см. Закрепляющий Артикул).Если вы не получаете ошибок ООМ или вам нужно подтвердить, является ли причиной этого утечка памяти, то единственный способ - это профилировать ваше приложение.

Я бы также постарался обеспечить следующее:

a) Все, что реализует Idisposable, утилизируется либо с помощью блока finally, либо с помощью оператора using, включая кисти, перья и т.д. (некоторые люди утверждают, что дополнительно нужно установить все равным nothing)

б) Все, что имеет метод close, снова закрывается с помощью finally или оператора using (хотя я обнаружил, что using не всегда закрывается в зависимости от того, объявили ли вы объект вне оператора using)

c) Если вы используете неуправляемый код / Windows API, то после этого они будут обработаны корректно.(у некоторых есть методы очистки для высвобождения ресурсов)

Надеюсь, это поможет.

Если вам нужно диагностировать утечку памяти в .NET, проверьте эти ссылки:

http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

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

У Microsoft также есть более новый инструмент для создания аварийных дампов, который заменит ADPlus и называется DebugDiag .

http://www.microsoft.com/downloads/details.aspx ?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3иdisplaylang=ru

Использование CLR Profiler от Microsoft http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en это отличный способ определить, какие объекты занимают память, какой поток выполнения приводит к созданию этих объектов, а также отслеживать, какие объекты где находятся в куче (фрагментация, LOH и т.д.).

Лучшее объяснение того, как работает сборщик мусора, содержится в книге Джеффа Рихтерса CLR через C# книга, (гл.20).Прочтение этой статьи дает отличную основу для понимания того, как сохраняются объекты.

Одной из наиболее распространенных причин случайного рутинга объектов является подключение событий вне класса.Если вы подключаете внешнее событие

например ,

SomeExternalClass.Changed += new EventHandler(HandleIt);

и забудьте отцепиться от него, когда будете утилизировать, тогда SomeExternalClass будет иметь ссылку на ваш класс.

Как упоминалось выше, Профилировщик памяти SciTech отлично показывает вам корни объектов, которые, как вы подозреваете, протекают.

Но есть также очень быстрый способ проверить определенный тип - просто использовать WnDBG (вы даже можете использовать это в окне VS.NET immediate при подключении):

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

Теперь сделайте что-то, что, по вашему мнению, приведет к удалению объектов этого типа (напримерзакройте окно).Здесь удобно иметь где-нибудь кнопку отладки, которая будет запускаться System.GC.Collect() пару раз.

Тогда беги !dumpheap -stat -type <TypeName> снова.Если число не уменьшилось или снизилось не так сильно, как вы ожидали, то у вас есть основание для дальнейшего расследования.(Я получил этот совет из семинара, проведенного Инго Раммер).

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

Почему люди думают, что утечка памяти в .NET - это не то же самое, что любая другая утечка?

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

Что касается .NET и других инструментов программирования, были идеи о сборе мусора и других способах минимизации ситуаций, которые приведут к утечке вашего приложения.Но лучший метод предотвращения утечек памяти заключается в том, что вам нужно понимать вашу базовую модель памяти и то, как все работает на используемой вами платформе.

Вера в то, что GC и другая магия исправят ваш беспорядок, - это короткий путь к утечкам памяти, и позже его будет трудно найти.

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

С другой стороны, в .NET многие люди думают, что GC все очистит.Что ж, это кое-что дает вам, но вы должны убедиться, что это так..NET оборачивает множество вещей, поэтому вы не всегда знаете, имеете ли вы дело с управляемым или неуправляемым ресурсом, и вам нужно убедиться, с чем вы имеете дело.Обработка шрифтов, ресурсов GDI, active Directory, баз данных и т.д. - это, как правило, то, на что вам нужно обратить внимание.

В управляемых терминах я готов рискнуть сказать, что это исчезнет, как только процесс будет остановлен / удален.

Однако я вижу, что у многих людей это происходит, и я действительно надеюсь, что этому придет конец.Вы не можете попросить пользователя закрыть ваше приложение, чтобы навести порядок!Взгляните на браузер, который может быть IE, FF и т.д., затем откройте, скажем, Google Reader, оставьте его на несколько дней и посмотрите, что произойдет.

Если затем вы откроете другую вкладку в браузере, перейдете на какой-нибудь сайт, а затем закроете вкладку, на которой размещалась другая страница, из-за которой произошла утечка браузера, как вы думаете, освободит ли браузер память?Не так обстоит дело с IE.На моем компьютере IE легко съест 1 гигабайт памяти за короткий промежуток времени (около 3-4 дней), если я использую Google Reader.Некоторые новостные страницы еще хуже.

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

Абсолютно.Кроме того, неиспользование метода .Dispose() на одноразовых предметах, когда это необходимо, может привести к утечке памяти.Самый простой способ сделать это - использовать блок using, потому что он выполняется автоматически .Dispose() в конце:

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

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

Все утечки памяти устраняются путем завершения работы программы.

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

Я соглашусь с Бернардом относительно того, что такое утечка памяти в .net.

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

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

Неуправляемый код сам по себе является чудовищем, и если в нем существует утечка, он будет следовать стандартному mem.определение утечки.

Также имейте в виду, что .NET имеет две кучи, одна из которых является кучей больших объектов.Я полагаю, что в эту кучу помещаются объекты размером примерно 85 тысяч или больше.Эта куча имеет другие правила жизненного цикла, чем обычная куча.

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

Что касается восстановления памяти при завершении процесса, если только вы не используете Win98 или его эквиваленты, все возвращается обратно в ОС при завершении.Единственными исключениями являются объекты, которые открываются между процессами, а другой процесс все еще имеет открытый ресурс.

COM-объекты могут быть сложными, хотя.Если вы всегда используете IDispose паттерн, ты будешь в безопасности.Но я наткнулся на несколько сборок взаимодействия, которые реализуют IDispose.Ключевым моментом здесь является вызов Marshal.ReleaseCOMObject когда ты закончишь с этим.COM-объекты по-прежнему используют стандартный подсчет ссылок COM.

Я нашел Профилировщик памяти .Net очень хорошая помощь при поиске утечек памяти в .Net.Это не бесплатно, как Microsoft CLR Profiler, но, на мой взгляд, быстрее и более по существу.A

Одно из определений таково: Невозможно освободить недоступную память, которая больше не может быть выделена новому процессу во время выполнения процесса выделения.В основном это можно вылечить с помощью методов ГК или обнаружить с помощью автоматизированных инструментов.

Для получения дополнительной информации, пожалуйста, посетите http://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.html.

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