Подробный анализ использования памяти файла сбоя Windows? - PullRequest
21 голосов
/ 19 января 2011

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

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

Редактировать: После обмена комментариями с Лексом Ли ниже я должен добавить: невоспроизводимо для нас (на данный момент). Это всего лишь один клиент дамп, ясно показывающий потребление неуправляемой памяти.

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

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

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

Мы использовали инструмент 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 или любого другого инструмента, могут действительно помочь! Кроме того, если вы не согласны с любым из моего анализа выше, сообщите нам! Спасибо!

Ответы [ 3 ]

10 голосов
/ 26 января 2011

Вы можете:

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

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

Правильный способ отследить утечку памяти - правильно использовать правило DebugDiag «Память и обработка утечки».

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

3 голосов
/ 19 января 2011

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

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

...