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 признака кода с душком: убей его и лови всё молча

Рекомендую книги по этой теме:

10 комментариев к VMMap вам в помощь

  • SWW

    “Мы видим кучу потоков, некоторые из которых выделяют себе аж 1Мб на стэк.” - это не они себе выделяют, это Windows им выделяет, так как они GUI-потоки (PsConvertToGuiThread в ntoskrnl.exe). Руссиновича и Соломона советую все-таки дочитать :)

    В целом ничего нового. Память можно посмотреть (и сдампить) также в ollydbg, petools, windbg и т.п. Performance counter’ы в Windows тоже не просто так сделаны, помогают много за чем следить.

    • SWW

      Про GUI-потоки я немного нагнал :) Windows, если я не ошибаюсь, для стека потока берет значение из PE-заголовка его процесса при условии, что в CreateThread не был передан параметр для размера стека данного потока.

      А GUI-потоки - это немного другая тема, стек там действительно Windows увеличивает :)

      • Что такое “GUI-потоки” я не знаю, но не думаю, что система увеличивает стэки самостоятельно. Всё должна брать из PE-заголовка.
        Мы можем его поменять или указывать конкретный размер при создании потока, чтобы выделять меньше стэк.
        Но большинство программ не заморачиваются этим - у них просто 1Мб по умолчанию так и стоит.

        • SWW

          GUI-потоки - это потоки, которые позвали хотя бы один раз любую гуевую функцию. Отличаются от обычных размером ядерного стека, специальной структурой(W32THREAD или типа того) и наличием ShadowTable.

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

  • Just FYI - часть утилит, описанных в этой статье вполне работают и под виндой. Мы используем google performance tools + пачка скриптов для анализа потребления памяти

    • Проблема этих тулзов и google performance tools в частности в том, что с ними надо перекомпилировать продукт. А это непросто и вообще отдельная большая задача, если сотня исполняемых файлов и dll компиляется. Но согласен, что если они встроены в билд, то с ними гораздо лучше профилироваться.
      Но под виндой, например, можно использовать umdh и gflags, чтобы получить калстэки и отслеживать выделения - даже без перекомпиляции.

      • не помню как под виндой, а под линуксом - ничего перекомпилировать не надо

        • Из описания: “Поиск утечек памяти с помощью tcmalloc очень прост — надо слинковать программу с этой библиотекой…”

          Или там есть еще другой режим работы без доступа к исходному коду? Но тогда это получится копия umdh.

  • mihapro

    Очень полезные статьи, спасибо! Жду продолжения.
    ps. прями походу и применяю полученные занания в работе на боевом коде :) Сильно выручает.

  • Сергей

    Наконец нормальная статья про эту утилиту, все просто расписанно и четко.

    Автору спасибо.

Ответить

 

 

 

Вы можете использовать эти HTML тэги

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>