VMMap вам в помощь
Недавно я начал тут новую серию постов про тулзы, помогающие в отладке и анализе приложений. Начал я со статьи Application verifier - простая бесплатная мощь, а это вторая статья из этой серии.
Сегодня речь пойдёт не про отладку, а про анализ приложений. Сегодня я расскажу про VMMap - одну из программ из комплекта Sysinternals от Марка Русиновича.
VMMap - это очень простая тулза, выполняющая ровно одну задачу - анализ расхода памяти в процессе.
Вы думаете, что знаете всё про то, куда расходуется память в вашей программе?
Тогда попробуйте сейчас отложить чтение, задуматься и ответить на простой вопрос - куда и как расходуется память в вашем приложении?
Уверен, вы будете думать про собственные выделения памяти, а также, возможно, про потоки, если читали мою недавнюю статью Потоки и память. Но учтёте ли вы всё?
Так вот, проще не думать, а запустить VMMap и посмотреть. Удивительно, но в большинстве случаев оказывается, что ваша собственная выделенная память в вашем же приложении - это меньше половины от общего расхода памяти. А во многих случаях это вообще 10-20%.
Итак, куда же расходуется память в приложении?
Давайте выберем распространенное приложение и проанализируем его. Возьмем для примера Skype и откроем его в VMMap.
Посмотрите на скриншот.
Все картинки кликабельны.
Итак, в списке сверху мы видим общую информацию по типам выделенной памяти. Там есть: Image, Private, Shareable, Mapped file, Heap, Stack, System, а также можно увидеть свободную память и максимальный кусок свободной памяти.
В строке Total видно, что всего процесс зарезервировал для себя 214Мб памяти. При этом закомитил из них 125Мб, а Working Set (реально используемая память) у него 55.9Мб.
Как видите, в процессе использовано 7 типов памяти. При этом память, выделенная приложением - это Private (желтая на графиках) и она занимает всего около 25% от всей памяти. А что же остальное?
На первом месте по расходу - Image (фиолетовый цвет). Могу вас уверить, что в большинстве приложений Image на первом месте. Только в очень требовательных к памяти приложениях (игры, обработка видео, видео проигрыватели) Image может быть на втором месте.
Выделим строку Image и посмотрим, что именно “съедает” память.
Image - это память, отданная под dll и exe-файлы. Каждая dll должна быть замаплена на память приложения, так что хоть она и не будет грузиться с диска или копироваться в памяти, но она отъест некоторый кусок виртуальной памяти приложения. Также многие dll выделяют внутри себя память, так что они еще и расходуют Working Set приложения.
В Image секции с большим отрывом лидирует Skype.exe - файл аж 23Мб и весь загружен в память. Также можно увидеть, что shell32.dll, ntdll.dll, x86_microsoft… и ntdll.dll для 64 битов занимают еще больше 15Мб в памяти в больше 2Мб в Working set.
Для меня до сих пор остается загадкой shell32.dll. Это одна из самых крупных dll в Windows и при этом она загружена во многие приложения. Причем большинство приложений оттуда используют 1-2 функции (SHGetFolder, например). При этом сам факт загрузки этой dll сразу отнимает 13Мб Virtual Memory и 200-400К Working Set. Этакий скрытый Windows-монстр, порождение плохого дизайна Windows API. К счастью в новых версиях Windows некоторые функции из shell32.dll вынесены в отдельные небольшие dll - уже прогресс.
Далее мы можем посмотреть mapped files:
Тут очень занятные цифры. У нас почти 14Мб виртуальной памяти и около 1Мб Working Set заняты замапленными системными файлами. Удивительно, но большинство даже простейших приложений имеют эти замапленные файлы. Попробуйте запустити hello world и вы это увидите.
Теперь давайте посмотрим стэки потоков.
Мы видим кучу потоков, некоторые из которых выделяют себе аж 1Мб на стэк. Всего же на них тратится 33Мб виртуальной памяти и 748Кб Working Set. Огромный разрыв между виртуальной памятью и Working Set говорит, что для стэков зарезервировано слишком много памяти. Им столько не нужно.
Зачем нужна эта информация? Например, по идентификатору потока в WinDBG или в Process Explorer можно посмотреть колстэки и понять, что это за поток, чтобы уменьшить ему размер стэка в коде при создании.
Ну и посмотрим еще свободные блоки памяти.
На этой картинке мы видим список доступных блоков памяти и их размеры. Обычно эта информация не сильно-то полезна, но бывают исключения.
Например, это окно позволяет находить проблемы с base address у dll-файлов. Если для dll прописать плохой base address, то она может загрузиться куда-нибудь в память посередине процесса и разбить его адресное пространство пополам.
Это приводит к тому, что у процесса свободно почти 2Гб памяти, а даже 1Гб одним большим блоком выделить нельзя, т.к. ровно посередине загрузилась dll и разбила 2 Гб на 2 куска по 1Гб. К сожалению такое встречается нередко.
Например, на моей Windows7 и IE и Firefox показывают максимальный единый блок памяти около 1.3Гб, хотя свободно 1.8Гб. Как раз из-за того, что одна из dll влезла в середину адресного пространства.
Так что будьте очень осторожны, прописывая base address и проверяйте что получилось на практике.
Вот, в общем-то и всё про VMMap. Тулза предельно простая, но дает полную информацию про используемую память.
Те цифры и указатели на память, что вы видите в ее интерфейсе - их можно использовать в дебагерах, в WinDBG, например, для получения информации о памяти или потоках.
А информация о загруженных dll должна стать отправной точкой в анализе exe файла через тулзу Dependencies Viewer или еще какую.
Так что VMMap - это только начало анализа. Её можно использовать для того, чтобы выявить проблему. А детально с ней разобраться и вылечить - это задачи других программ.
А про другие полезные программы я тоже расскажу со временем, оставайтесь на линии
Понравилась статья? Подпишись на RSS!
Похожие записи:
Application verifier - простая бесплатная мощь
Потоки и память
Знай свою память
Книги + программисты = деньги
Не будите спящего программиста
2 признака кода с душком: убей его и лови всё молча
Рекомендую книги по этой теме:
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
“Мы видим кучу потоков, некоторые из которых выделяют себе аж 1Мб на стэк.” - это не они себе выделяют, это Windows им выделяет, так как они GUI-потоки (PsConvertToGuiThread в ntoskrnl.exe). Руссиновича и Соломона советую все-таки дочитать
В целом ничего нового. Память можно посмотреть (и сдампить) также в ollydbg, petools, windbg и т.п. Performance counter’ы в Windows тоже не просто так сделаны, помогают много за чем следить.
Про GUI-потоки я немного нагнал
Windows, если я не ошибаюсь, для стека потока берет значение из PE-заголовка его процесса при условии, что в CreateThread не был передан параметр для размера стека данного потока.
А GUI-потоки - это немного другая тема, стек там действительно Windows увеличивает
Что такое “GUI-потоки” я не знаю, но не думаю, что система увеличивает стэки самостоятельно. Всё должна брать из PE-заголовка.
Мы можем его поменять или указывать конкретный размер при создании потока, чтобы выделять меньше стэк.
Но большинство программ не заморачиваются этим - у них просто 1Мб по умолчанию так и стоит.
GUI-потоки - это потоки, которые позвали хотя бы один раз любую гуевую функцию. Отличаются от обычных размером ядерного стека, специальной структурой(W32THREAD или типа того) и наличием ShadowTable.
Конечно система не увеличивает стек, иначе бесконечные рекурсии до сих пор нас мучали. Собственно говоря, верхнее значение стека и служит для того, чтобы мы не увлекались рекурсиями.
Just FYI - часть утилит, описанных в этой статье вполне работают и под виндой. Мы используем google performance tools + пачка скриптов для анализа потребления памяти
Проблема этих тулзов и google performance tools в частности в том, что с ними надо перекомпилировать продукт. А это непросто и вообще отдельная большая задача, если сотня исполняемых файлов и dll компиляется. Но согласен, что если они встроены в билд, то с ними гораздо лучше профилироваться.
Но под виндой, например, можно использовать umdh и gflags, чтобы получить калстэки и отслеживать выделения - даже без перекомпиляции.
не помню как под виндой, а под линуксом - ничего перекомпилировать не надо
Из описания: “Поиск утечек памяти с помощью tcmalloc очень прост — надо слинковать программу с этой библиотекой…”
Или там есть еще другой режим работы без доступа к исходному коду? Но тогда это получится копия umdh.
Очень полезные статьи, спасибо! Жду продолжения.
Сильно выручает.
ps. прями походу и применяю полученные занания в работе на боевом коде
Наконец нормальная статья про эту утилиту, все просто расписанно и четко.
Автору спасибо.