Утечка памяти в смешанном режиме приложения C++ / CLR

У меня проблемы с медленной утечкой памяти в моем смешанном режиме c++/CLR .NET-приложения.

(Это собственные статические библиотеки C++, связанные с приложением VS2008 C++/CLR Windows Forms с параметром компилятора "/clr")

типичное поведение: приложение начинает использовать 30 МБ (собственной памяти). Затем утечки памяти замедляются, скажем, МБ каждый час при работе под симулированной большой нагрузкой. Это имитирует приложение жить в течение нескольких дней или недель.

Я пробовал использовать несколько инструментов для отслеживания утечек памяти, включая отладочные материалы CRT, поставляемые с библиотеками CRT Visual Studio. Я также использовал коммерческий инструмент обнаружения утечек ("валидатор памяти").

оба сообщают о незначительных утечках памяти при выключении (несколько незначительных записей, которые составляют несколько КБ, о которых я не беспокоюсь). Кроме того, я вижу при запуске, что отслеживаемая память, похоже, не так много (поэтому я не считаю, что это просто память, которая удерживается и освобождается только при выходе из приложения). Я получаю около 5 Мб указанной памяти (из общего числа > 30 МБ).

инструмент (валидатор памяти) настроен для отслеживания всего использования памяти (включая malloc, new, virtual memory allocation и целую кучу других типов выделения памяти). В основном, каждый параметр, для которого была выбрана память для отслеживания.

образ .NET сообщает, что он использует около 1,5 МБ памяти (от perfmon).

вот еще немного информации: у нас есть версия приложения, которая работает как собственное консольное приложение (чисто собственное - не CLR вообще). Это 95% то же самое, что и смешанный режим, за исключением без пользовательского интерфейса. Это, похоже, не утечка памяти вообще, и пики вокруг 5MB частных байтов.

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

еще одна часть головоломки: я нашел это, что относится к утечкам памяти в приложениях смешанного режима при таргетинге 2.0 framework (который Я): http://support.microsoft.com/kb/961870

к сожалению, детали раздражающе скудны, поэтому я не уверен, что это актуально. Я попытался нацелиться на 3.5 framework вместо 2.0, но все еще имел ту же проблему (возможно, я не сделал это правильно).

У кого-нибудь есть предложения?

несколько вещей, которые могли бы помочь мне:

  • есть ли какие-либо другие выделения памяти, которые я не отслеживаю?
  • как получилось цифры не сходятся? Я получаю 5 Мб использования памяти CRT, 1,5 МБ памяти .NET, так как же все приложение использует 30 МБ частных байтов? Это все связано с .NET framework? Почему я не вижу их в инструменте утечки? Не выиграл .Сетка появится как некую выделенную память?
  • любые другие инструменты обнаружения утечек, которые хорошо работают с приложениями смешанного режима?

Спасибо за помощь

Джон

5 ответов


ОК, я, наконец, нашел проблему.

Это было вызвано неправильной настройкой для /EH (обработка исключений).

в основном, в приложениях .NET со смешанным режимом вам нужно убедиться, что все статически связанные библиотеки скомпилированы с /EHa вместо default /EHs.

(само приложение также должно быть скомпилировано с /EHa, но это задано - компилятор сообщит об ошибке, если вы его не используете . Проблема при связывании в другие статические родной библиотеки.)

проблема в том, что исключения, пойманные в управляемом бит приложения, которые были брошены в собственных библиотеках, скомпилированных с /EHs, в конечном итоге не обрабатывают исключение правильно. Деструкторы для объектов C++ вызываются неправильно.

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


Как говорил Спенс, но для C++ / CLI ;)....

для любого объекта, который вы используете в C++/CLI, если вы создаете больше этого объекта из кода C++, вы должны попытаться использовать seymantics распределения стека, даже если это своего рода магия компилятора, он может настроить вложенные операторы __try {} __finally {}, которые вы можете использовать из собственного кода (то есть настроить их таким образом, чтобы не потерять вызов Dispose).

исполнение по статья в проекте кода здесь на семантике распределения стека C++/CLI довольно хороша и углубляется в то, как эмулировать с помощью{}.

вы также должны убедиться, что удалить любой объект, который implment IDisposable, поскольку вы не можете вызвать Dispose в C++/CLI, delete делает это за вас, если вы не используете семантику стека..

Я обычно вызываю Close себя на потоках и пытаюсь назначить nullptr, когда я закончу с объектом, на всякий случай.

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

в крайнем случае (или, может быть, сначала:), одна вещь, которую я сделал в прошлом, это использовать API профилировщика CLR,вот еще статья о том, как это сделать, писатель автора (Джей Хилярд) имеет пример, который отвечает;

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

должен дать вам лучшую идею, чем какой-то профилировщик товаров, я заметил, что они могут иногда вводить в заблуждение в зависимости от вашего порофайла распределения (кстати. следите за большой проблемы с кучей объектов, > ~83kb объекты специально обрабатываются, в этом случае я бы рекомендовал, выходя из большой кучи объектов :).

учитывая ваши комментарии, еще несколько вещей...

Я опубликовал раньше о загрузке изображения не взимая квоту или любую другую статистику, что это означает, Вам может потребоваться отслеживать некоторые проблемы с дескриптором или загрузчиком (см. loader lock в конечном итоге), но до этого вы можете попробовать настроить некоторые Ограниченные Области Выполнения, они может творить чудеса, но также, к сожалению, трудно ретро-вписаться в не чистый код.

Это последние MSDN Mag, статья документа много perfmon типа sperlunking памяти (followup для этот старый).

с VS Perf Blog, они показывают, как использовать SOS в visual studio, что может быть удобно, чтобы отслеживать Rouge DLL, связанные сообщения также хороши.

блог Маони Стивена и компанию, он говорит, что он в команде perf, но по существу 100% его сообщений по отношению к GC так много, что он может хорошо написать его.

Рик Байерс является разработчиком с командой диагностики CLR, многие из его блог-приятелей также являются хорошими источниками, однако я настоятельно рекомендую также ссылаться на совершенно новый dev / форум диагностики. Недавно они расширили рамки своих обсуждений.

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

(в частности, эти пертикулярные статы, возможно, не дают вам глобального представления о том, что делает ваш код, я могу сказать, что недавно я нашел (даже с .двоичные файлы net4beta, профилировщик из этой компании, довольно хорошо, он способен выводить родные / управляемые утечки из его трассировок профиля, возвращает вас к точным исходным строкам (даже если оптимизировано, довольно приятно (и у него есть 30-дневная пробная версия)))).

удачи!! Надеюсь, что это поможет, это только свежо в моем уме, так как я делаю большую часть той же работы прямо сейчас;)


попробуйте: DebugDiags.
После генерации некоторых дампов памяти он даст вам приятное лето того, какая память была выделена, и в зависимости от нахождения вашего PDB, он может сказать вам, кем он был выделен.


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

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


возможно ли, что вы пропустили некоторые disposers, может произойти, если вы используете GDI+ и многие другие API.

Если вы запустите инструмент статического анализа FXCop, у него есть правило, чтобы проверить, вызвали ли вы инструкции dispose (или использовали "using") для ваших объектов, которые предоставляют интерфейс. В .Net если функция использует неуправляемый код, она обычно предоставляет метод dispose или close для предотвращения утечки ресурса/памяти.