VMMap вам в помощь

Сегодня я расскажу про 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% от всей памяти. А что же остальное?

VMMap

На первом месте по расходу — 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 Гб. К сожалению такое встречается нередко.

Например, на моей Windows IE и Firefox показывают максимальный единый блок памяти около 1.3 Гб, хотя свободно 1.8 Гб.  Как раз из-за того, что одна из dll влезла в середину адресного пространства.

Так что будьте очень осторожны, прописывая base address и проверяйте что получилось на практике.

Вот, в общем-то и всё про VMMap. Тулза предельно простая, но дает полную информацию про используемую память.
Те цифры и указатели на память, что вы видите в ее интерфейсе — их можно использовать в дебагерах, в WinDBG, например, для получения информации о памяти или потоках.

А информация о загруженных dll должна стать отправной точкой в анализе exe файла через тулзу Dependencies Viewer или еще какую.

Так что VMMap — это только начало анализа. Её можно использовать для того, чтобы выявить проблему. А детально с ней разобраться и вылечить — это задачи других программ.

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

Оставить комментарий