Подтвердить что ты не робот

Подробный анализ использования памяти файла дампа сбоев Windows?

Мы получили от клиента собственный (полный) файл аварийного дампа. Открытие его в отладчике Visual Studio (2005) показывает, что у нас был сбой, вызванный вызовом realloc, который пытался выделить блок размером 10 МБ. Файл дампа был необычайно большим (1,5 ГБ - обычно они больше похожи на 500 МБ).

Таким образом, мы заключаем, что у нас есть память "утечка" или "беглые выделения", которые либо полностью исчерпали память процесса, либо, по крайней мере, фрагментировали его достаточно значительно для сбоя realloc. (Обратите внимание, что этот realloc был для операции, которая распределяла буфер регистрации, и мы не удивлены, что она не сработала здесь, потому что 10 МБ за один раз будет одним из больших распределений, которые мы делаем отдельно от некоторых очень больших довольно неизменных буферов - - сама проблема, вероятно, не имеет ничего общего с этим конкретным распределением.)

Изменить: После обмена комментариями с Lex Lex ниже, я должен добавить: Это не воспроизводится для нас (на данный момент). Это всего лишь один дамп клиента, который явно показывает потребление памяти беглых.

Основной вопрос:

Теперь у нас есть файл дампа, но как мы можем определить, что вызвало чрезмерное использование памяти?

Что мы сделали до сих пор:

Мы использовали инструмент DebugDiag для анализа файла дампа (так называемый анализатор давления памяти), и вот что мы получили:

Report for DumpFM...dmp

Virtual Memory Summary
----------------------
Size of largest free VM block   62,23 MBytes 
Free memory fragmentation       81,30% 
Free Memory                     332,87 MBytes   (16,25% of Total Memory) 
Reserved Memory                 0 Bytes   (0,00% of Total Memory) 
Committed Memory                1,67 GBytes   (83,75% of Total Memory) 
Total Memory                    2,00 GBytes 
Largest free block at           0x00000000`04bc4000 

Loaded Module Summary
---------------------
Number of Modules       114 Modules 
Total reserved memory   0 Bytes 
Total committed memory  3,33 MBytes 

Thread Summary
--------------
Number of Threads       56 Thread(s) 
Total reserved memory   0 Bytes 
Total committed memory  652,00 KBytes 

Это было просто для получения небольшого контекста. Что более интересно, я считаю:

Heap Summary
------------
Number of heaps         26 Heaps 
Total reserved memory   1,64 GBytes 
Total committed memory  1,61 GBytes 

Top 10 heaps by reserved memory
-------------------------------
0x01040000           1,55 GBytes        
0x00150000           64,06 MBytes        
0x010d0000           15,31 MBytes        
...

Top 10 heaps by committed memory
--------------------------------                              
0x01040000       1,54 GBytes 
0x00150000       55,17 MBytes 
0x010d0000       6,25 MBytes  
...            

Теперь, глядя на кучу 0x01040000 (1,5 ГБ), мы видим:

Heap 5 - 0x01040000 
-------------------
Heap Name          msvcr80!_crtheap 
Heap Description   This heap is used by msvcr80 
Reserved memory      1,55 GBytes 
Committed memory     1,54 GBytes (99,46% of reserved)  
Uncommitted memory   8,61 MBytes (0,54% of reserved)  
Number of heap segments             39 segments 
Number of uncommitted ranges        41 range(s) 
Size of largest uncommitted range   8,33 MBytes 
Calculated heap fragmentation       3,27% 

Segment Information
-------------------
Base Address | Reserved Size   | Committed Size  | Uncommitted Size | Number of uncommitted ranges | Largest uncommitted block | Calculated heap fragmentation 
0x01040640        64,00 KBytes      64,00 KBytes   0 Bytes            0                              0 Bytes                     0,00% 
0x01350000     1.024,00 KBytes   1.024,00 KBytes   0 Bytes            0                              0 Bytes                     0,00% 
0x02850000     2,00 MBytes       2,00 MBytes       0 Bytes            0                              0 Bytes                     0,00% 
...

Что это за информация о сегменте?

Посмотрите на перечисленные распределения:

Top 5 allocations by size
-------------------------
Allocation Size - 336          1,18 GBytes     
Allocation Size - 1120004      121,77 MBytes    
...

Top 5 allocations by count
--------------------------
Allocation Size - 336    3760923 allocation(s) 
Allocation Size - 32     1223794 allocation(s)  
...

Мы видим, что, по-видимому, куча MSVCR80 имеет 3,760,923 распределения при 336 байтах. Это делает довольно ясным, что мы зачистили нашу память множеством небольших распределений, но как мы можем получить дополнительную информацию о том, где эти распределения пришли из?

Если мы каким-то образом можем пробовать некоторые из этих адресов размещения, а затем проверять, где в образе процесса эти адреса используются, тогда - если предположить, что значительная часть этих распределений несет ответственность за нашу "утечку" - мы могли бы узнайте, откуда взялись эти беглые отчисления.

К сожалению, я действительно не знаю, как получить дополнительную информацию из дампа в настоящий момент.

Как я могу проверить эту кучу, чтобы увидеть некоторые адреса размещения "336"?

Как я могу найти дамп для этих адресов и как узнать, какая переменная указателя (если есть) в дампе удержала эти адреса?

Любые советы по использованию DebugDiag, WinDbg или любого другого инструмента действительно могут помочь! Кроме того, если вы не согласны с каким-либо из моих анализов выше, дайте нам знать! Спасибо!

4b9b3361

Ответ 1

Вы можете:

  • просмотрите эти блоки из 336 байтов, чтобы узнать, сообщает ли вам контент о том, что их выделило. Для этого я обычно использую windbg. Сначала запустите команду !heap -stat -h 0x01040000, которая даст вам размер блока, а затем передайте этот размер до размера !heap -flt s, который отобразит все блоки этого размера. Затем вы можете заглянуть в блок с помощью любой команды, которая отображает память (например, dc).
  • Вы не можете воспроизвести проблему, но можете посмотреть другой дамп, который выделяет блоки такого размера. Сначала активируйте функцию backtrace стека с помощью утилиты gflags.exe (gflags -i your.exe +ust). Затем запустите приложение, получите дамп и используйте !heap -flt s, чтобы перечислить блоки. Затем команда !heap -p -a blockaddress выгружает стек функций, которые выделяют блок.

Ответ 2

В windbg вы можете попробовать использовать !heap -l, который должен сканировать кучи (требуется некоторое время, может быть способ ограничить поиск определенной кучей, чтобы ускорить его) и найти все занятые блоки, которые не являются ссылки в любом месте. Оттуда откройте окно памяти (alt + 5) и посмотрите на некоторые из записей, которые соответствуют вашему размеру размещения, который, как вы подозреваете, является вашей утечкой. С некоторой удачей могут быть некоторые общие шаблоны, которые могут помочь вам определить, какие данные или лучше, но некоторые строки ascii, которые вы можете разместить сразу.

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

Ответ 3

Сколько дампов у вас сейчас?

Правильный способ отслеживания утечки памяти - это правильное использование правила DebugDiag Memory и Handle Leak.

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