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

StackOverflow https://stackoverflow.com/questions/1089296

Вопрос

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Спасибо за любую помощь

Джон

Это было полезно?

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Этот недавний MSDN Маг, в документе статьи много памяти типа perfmon (продолжение для этот старший).

Из Блог VS Perf, они показывают, как использовать SOS в Visual Studio, что может быть полезно для отслеживания DLL-библиотек Rouge, соответствующие сообщения также хороши.

Блог Маони Стивена и компания, Он говорит, что входит в команду производительности, но по сути 100% его постов настолько связаны с GC, что он вполне может это написать.

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

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

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

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

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

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

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

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

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

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