Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Утилита дампа кучи в режиме пользователя (UMDH) работает с операционной системой для анализа выделений кучи Windows для определенного процесса. UMDH определяет, какая функция в конкретном процессе вызывает утечку памяти.
UMDH включен в средства отладки для Windows. Полные сведения см. в разделе UMDH.
Подготовка к использованию UMDH
Если вы еще не определили, какой процесс вызывает утечку памяти, сначала сделайте это. Дополнительные сведения см. в статье "Использование монитора производительности для поиска утечки памяти User-Mode".
Наиболее важными данными в журналах UMDH являются трассировки стека при выделении кучи. Чтобы определить, является ли процесс утечкой памяти кучи, проанализируйте эти трассировки стека.
Прежде чем использовать UMDH для отображения данных трассировки стека, необходимо использовать GFlags для правильной настройки системы. GFlags включен в средства отладки для Windows.
Следующие параметры GFlags обеспечивают трассировку стека UMDH:
В графическом интерфейсе GFlags выберите вкладку "Файл изображения", введите имя процесса (включая расширение имени файла), нажмите клавишу TAB, выберите "Создать базу данных трассировки стека пользовательского режима" и нажмите кнопку "Применить".
Или, эквивалентно, используйте следующую командную строку GFlags, где imageName — это имя процесса (включая расширение имени файла):
gflags /i ImageName +ust
Используйте эту команду для очистки параметров GFlag после завершения. Дополнительные сведения см. в разделе "Команды GFlags".
gflags /i ImageName -ust
По умолчанию объем собираемых данных трассировки стека ограничен 32 МБ на процессоре x86 и 64 МБ на процессоре x64. Если необходимо увеличить размер этой базы данных, выберите вкладку "Файл изображения " в графическом интерфейсе GFlags, введите имя процесса, нажмите клавишу TAB, установите флажок Stack Backtrace (Megs), введите значение (в МБ) в связанном текстовом поле и нажмите кнопку "Применить". Увеличьте эту базу данных только при необходимости, так как она может истощить ограниченные ресурсы Windows. Если вам больше не требуется больший размер, верните этот параметр в исходное значение.
Если вы изменили флаги на вкладке "Системный реестр ", необходимо перезапустить Windows, чтобы внести эти изменения в силу. Если вы изменили флаги на вкладке "Файл изображения ", необходимо перезапустить процесс, чтобы внести изменения в силу. Изменения на вкладке "Флаги ядра " эффективны немедленно, но они теряются при следующем перезапуске Windows.
Перед использованием UMDH необходимо иметь доступ к соответствующим символам приложения. UMDH использует путь символа, указанный переменной среды _NT_SYMBOL_PATH. Задайте эту переменную равным пути, содержащего символы для приложения. Если вы также включаете путь к символам Windows, анализ может быть более полным. Синтаксис для этого пути символов совпадает с синтаксисом, используемым отладчиком; дополнительные сведения см. в пути символов.
Например, если символы для приложения находятся в C:\MySymbols, и вы хотите использовать общедоступное хранилище символов Майкрософт для символов Windows, используя C:\MyCache в качестве нижнего хранилища, вы будете использовать следующую команду, чтобы задать путь к символам:
set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*https://msdl.microsoft.com/download/symbols
Кроме того, чтобы обеспечить точные результаты, необходимо отключить кэширование BSTR. Для этого задайте переменную среды OANOCACHE равным 1 (1). Сделайте этот параметр перед запуском приложения, выделение которого необходимо отслеживать.
Если необходимо отслеживать выделения, сделанные службой, необходимо задать OANOCACHE в качестве системной переменной среды, а затем перезапустить Windows, чтобы этот параметр вступил в силу.
Обнаружение увеличения распределения кучи с помощью UMDH
После выполнения этих подготовительных действий, вы можете использовать UMDH для получения информации о выделении памяти в куче процесса. Для этого выполните следующую процедуру:
Определите идентификатор процесса (PID) для процесса, который требуется исследовать.
Используйте UMDH для анализа выделений памяти в куче для этого процесса и сохранения результатов в файле журнала. Используйте переключатель -p с PID и переключатель -f с именем файла журнала. Например, если идентификатор пин-кода равен 124, и вы хотите назовите файл журнала Log1.txt, используйте следующую команду:
umdh -p:124 -f:log1.txt
Откройте файл журнала с помощью Блокнота или другой программы. Этот файл содержит стек вызовов для каждого выделения кучи, количество выделений, сделанных стеком вызовов, и количество байтов, потребляемых стеком вызовов.
Поскольку вы ищете утечку памяти, содержимого одного файла журнала будет недостаточно. Чтобы определить, какие выделения растут, необходимо сравнить файлы журналов, записанные в разное время.
UMDH может сравнить два разных журнала и отобразить изменения в соответствующих размерах выделенной памяти. Для перенаправления результатов в третий текстовый файл можно использовать знак больше (>). Вы также можете включить параметр -d, который преобразует значения количества байтов и выделений из шестнадцатеричных в десятичные. Например, чтобы сравнить Log1.txt и Log2.txt, сохраняя результаты сравнения с файлом LogCompare.txt, используйте следующую команду:
umdh log1.txt log2.txt > logcompare.txt
Откройте файл LogCompare.txt. Его содержимое выглядит следующим образом:
+ 5320 ( f110 - 9df0) 3a allocs BackTrace00B53 Total increase == 5320
Для каждого стека вызовов (с меткой BackTrace) в файлах журнала UMDH выполняется сравнение между двумя файлами журнала. В этом примере первый файл журнала (Log1.txt) записал 0x9DF0 байтов, выделенных для BackTrace00B53, при этом второй файл журнала записал 0xF110 байтов, что означает, что между записью двух журналов было выделено 0x5320 дополнительных байт. Байты были получены из стека вызовов, определяемого BackTrace00B53.
Чтобы определить, что находится в этом бектрейсе, откройте один из исходных файлов журнала (например, Log2.txt) и найдите "BackTrace00B53". Результаты будут похожи на эти данные:
00005320 bytes in 0x14 allocations (@ 0x00000428) by: BackTrace00B53 ntdll!RtlDebugAllocateHeap+0x000000FD ntdll!RtlAllocateHeapSlowly+0x0000005A ntdll!RtlAllocateHeap+0x00000808 MyApp!_heap_alloc_base+0x00000069 MyApp!_heap_alloc_dbg+0x000001A2 MyApp!_nh_malloc_dbg+0x00000023 MyApp!_nh_malloc+0x00000016 MyApp!operator new+0x0000000E MyApp!DisplayMyGraphics+0x0000001E MyApp!main+0x0000002C MyApp!mainCRTStartup+0x000000FC KERNEL32!BaseProcessStart+0x0000003D
В выходных данных UMDH показано, что в стеке вызовов было выделено в общей сложности 0x5320 байт (десятичное значение 21280). Эти байты были выделены из 0x14 (десятичное 20) отдельных выделений по 0x428 (десятичное 1064) байт каждое.
Стек вызовов получает идентификатор BackTrace00B53, а вызовы в этом стеке отображаются. При просмотре стека вызовов вы увидите, что подпрограмма DisplayMyGraphics выделяет память через новый оператор, который вызывает подпрограмму malloc, которая использует библиотеку времени выполнения Visual C++ для получения памяти из кучи.
Определите, какой из этих вызовов является последним, который будет явно отображаться в исходном коде. В этом случае это, вероятно, оператор new, потому что вызов malloc произошел в рамках реализации new, а не как отдельное выделение. Таким образом, этот экземпляр нового оператора в подпрограмме DisplayMyGraphics неоднократно выделяет память, которая не освобождается.