Как detect.NET утечка памяти WPF или длительный запуск GC?

У меня есть очень странная ситуация и проблема:

  • приложение .NET 4.0 для редактирования диаграмм (WPF).

  • работает нормально на моем ПК: 8GB RAM, 3.0 GHz, i7 quad-core.

  • при создании объектов (в основном узлов и соединителей диаграммы, а также всей информации отмены/повтора) TaskManager показывает, как и ожидалось, некоторые "скачки" использования памяти (вверх и вниз).

  • эти mem-использование "прыжки" также остается выполненным после завершения взаимодействия с пользователем. Может быть, это очистка ГХ/regorganizing памяти?

  • чтобы увидеть, что происходит, я использовал профилировщик Муравьев mem, но несколько это предотвращает эти "прыжки" после взаимодействия с пользователем.

проблема: он зависает/зависает после секунд или минут использования в некоторых медленных/слабых лапто/нетбуках моих бета-тестеров (под 2 ГГц скорости и под 2 ГБ ОЗУ). Я думал об утечке памяти., но...

EDIT 1: Кроме того, есть случай, когда использование памяти растет и растет до коллапса (только на медленных машинах).

  • в машине режима Windows XP (VM в Win 7) С только 512MB ОЗУ, назначенным, он отлично работает без использования mem - "прыжков" после взаимодействия с пользователем (нет очистки GC?!).

EDIT 2: Проблема усугубляется, когда в системе запущены другие тяжелые программы (например, Visual Studio, Office и открытые веб-страницы). Даже не первый символ диаграммы может быть создан, когда использование памяти взлетает, как ракета в космос (сотни Мб, потребляемых в секундах). Кто-нибудь с подобным опытом? что это были за стратегии?

Итак, у меня действительно большие проблемы, потому что я не могу воспроизвести ошибку, только вижу это странное поведение (прыжки mem), и инструмент, который должен показать мне, что происходит, скрывает проблему (например, "парадокс наблюдателя").

любые идеи о том, что происходит и как решить это?

EDIT 3: Этот скриншот профилировщика памяти Муравьев показывает, что огромное потребление ОЗУ (в крещендо), если из неуправляемых ресурсов.

enter image description here

но что может потреблять столько памяти, так быстро??!!!

3 ответов


Это предполагает, что вы, вероятно, создаете много "мусора" - в основном, создавая и позволяя многим объектам быстро выходить из области видимости, но которые занимают достаточно много времени, чтобы попасть в Gen1 или Gen2. Это накладывает большую нагрузку на GC, что в свою очередь может вызвать зависания и зависания на многих системах.

чтобы увидеть, что происходит, я использовал профилировщик Муравьев mem, но несколько это предотвращает эти "прыжки" после взаимодействия с пользователем.

причина этого профилировщик (муравьи), в частности, может маскировать это поведение, так как он заставляет полный GC каждый раз, когда вы делаете снимок памяти. Это заставит его выглядеть так, как будто нет "утечки памяти" (поскольку ее нет), но не показывает общее давление памяти на систему.

инструмент PerfView может использоваться для исследования поведения GC во время выполнения процесса. Это поможет вам отслеживать количество GCs, которые происходят, и состояние приложения на данный момент в время.


то, что вы описываете, является полностью нормальным поведением для программы .NET, нет никаких признаков того, что с вашим кодом что-то не так.

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

рабочий набор-это объем ОЗУ, который использует ваш процесс. Каждый процесс получает 2 гигабайта виртуальный памяти для кода и данных. Даже на вашем виртуальном XP box с только 512 МБ оперативной памяти. Однако все эти процессы имеют только установленный объем ОЗУ для работы. На скромной машине, которая может быть всего лишь один гигабайт.

очевидно, что работает несколько процессов, каждый с гигабайтами виртуальной памяти только с гигабайтом реальные память занимает какое-то волшебство. Это предусмотрено операционной системой Windows виртуализация оперативной памяти. Другими словами, он создает иллюзию для каждого процесса, что он работает самостоятельно на машине с 2 гигабайтами ОЗУ. Это делается с помощью функции пейджинговая, всякий раз, когда процесс должен читать или записывать память, операционная система захватывает кусок ОЗУ для обеспечения физической памяти.

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

очевидно, что это не бесплатно, диски довольно медленные, а подкачка-дорогостоящая операция. Вот почему низкие машины работают плохо, когда вы просите их запустить несколько больших программ. Реальная мера для этого также видна в TaskMgr.exe, но вы должны добавить его. Просмотр + выберите столбцы и отметьте "ошибка страницы delta". Наблюдать это номер во время выполнения процесса. Когда вы видите его всплеск, вы можете ожидать, что ваша программа сильно замедлится, а отображаемое использование памяти быстро изменится.

обращаясь к вашим наблюдениям:

создание объектов ... TaskManager показывает, как и ожидалось, некоторое использование памяти "прыгает"

Да, вы используете ОЗУ, поэтому рабочий набор идет вверх.

эти mem-использование "прыжки" также остается выполнение после взаимодействия с пользователем конец

нет slam dunk, но другие процессы получают больше времени для выполнения, используя ОЗУ в свою очередь и натыкаясь на некоторые из ваших. Проверьте Дельта-столбец ошибки страницы.

Я использовал профилировщик Муравьев mem, но несколько он предотвращает эти "прыжки" после взаимодействия с пользователем.

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

существует случай, когда использование памяти растет и растет до коллапса

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

в машине режима Windows XP (VM в Win 7) только с 512MB ОЗУ он работает отлично

Это, вероятно, потому, что вы не установили никаких больших программ на этом WM, которые конкурировали бы за ОЗУ. XP также был разработан для работы на машинах с очень маленькой памятью, он гладкий на машине с 256 МБ. Это определенно не относится к Vista / Win7, они были разработаны, чтобы воспользоваться современным аппаратным обеспечением машины. Функция, как Aero хороший глаз конфеты, но очень дорогой.

проблема хуже, когда система имеет некоторые другие тяжелые программы, работающие

Да, вы конкурируете с другими процессами, требующими много ОЗУ.

даже первый символ диаграммы не может быть создан в то время как использование памяти взлетает, как ракета

Да, вы видите, что страницы сопоставляются обратно в ОЗУ, перезагружаются из файла подкачки и ngen-ed .ni.dll файлы. Быстро увеличивая ваш рабочий набор снова. Вы также увидите, что номер дельты ошибки страницы достигает максимума.

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


трудно точно знать, что происходит, не видя ваш код, но вот несколько советов:

во-первых, некоторая информация о сборщике мусора. Самое главное знать, что GC недетерминирован, вы не можете знать, когда он будет работать. Даже вызов GC.Собирать () - это только предложение, а не команда. Куча Gen0 предназначена для объектов локальной области и часто собирается. Если объект переживает коллекцию Gen0, он будет перемещен в кучу Gen1. После немного куча Gen1 будет собрана, и если объект переживает коллекцию, он перемещается в кучу Gen2, которая реже собирается. По этой причине можно увидеть шаблон пилы в графе памяти, если вы выделяете много объектов, которые делают его в кучу Gen1 или Gen2.

используя такой инструмент, как Процесс Explorer изучите размер управляемых куч (Gen0, Gen1, Gen2 и большая куча объектов) и узнайте, где хранится память. Если у вас есть много короткоживущих объектов (куча Gen1) подумайте о способе повторного использования памяти вместо повторного выделения-что - то вроде объект бассейн работает хорошо для этого.

кроме того, попробуйте сравнить общий размер управляемых куч с общими частными байтами вашего приложения. Частные байты включают как управляемую, так и неуправляемую память, выделенную приложением. Если существует большая разница между размером управляемых куч и частными байтами, вероятно, что ваш приложение выделяет неуправляемые объекты (через графические объекты, потоки и т. д.), которые не удаляются правильно. Ищите объекты, которые реализуют IDisposable, но не имеют Dispose () вызывается.

другой проблемой может быть фрагментация кучи. Если приложение выделяет большие объекты, которые не могут поместиться в текущую кучу, оно запросит больше памяти из ОС. Решение, чтобы избежать этого, - выделить меньшие куски или память или выделить их последовательно блоки, а не случайным образом (подумайте array vs linked list). Такой инструмент, как профилировщик памяти муравьев, должен быть в состоянии сказать вам, что это происходит.

@ReedCopsey рекомендация PerfView (или его предшественник профилировщик CLR) является хорошей и даст вам лучшее представление о том, как выделяется ваша память.