Мы получили от клиента нативный (полный) файл дампа сбоя. Открытие его в отладчике Visual Studio (2005) показало, что у нас произошел сбой, вызванный вызовом realloc, который пытался выделить блок размером ~10MB. Файл дампа был необычно большим (1,5 ГБ - обычно они больше 500 МБ).
Поэтому мы пришли к выводу, что у нас есть "утечка" памяти или беглые выделения, которые либо полностью исчерпали память процесса, либо, по крайней мере, фрагментировали ее достаточно сильно, чтобы перераспределение не сработало. (Обратите внимание, что это перераспределение было выполнено для операции, которая выделяла буфер логирования, и мы не удивлены, что оно не сработало, потому что 10 МБ за один раз было бы одним из больших выделений, которые мы делаем, за исключением некоторых очень больших довольно неизменных буферов - сама проблема, скорее всего, не связана с этим конкретным выделением)
Edit: После обмена комментариями с Lex Li ниже, я должен добавить: Это не воспроизводимо для нас (на данный момент). Это всего лишь один клиентский дамп, явно демонстрирующий бешеное потребление памяти.
Теперь у нас есть файл дампа, но как мы можем определить, что вызвало чрезмерное использование памяти?
Мы использовали инструмент DebugDiag для анализа файла дампа (так называемый Memory Pressure Analyzer), и вот что мы получили:
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%
...
Что это вообще за Segment Information?
Глядя на перечисленные выделения:
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 или любого другого инструмента могут очень помочь! Также, если вы не согласны с каким-либо моим анализом выше, дайте нам знать! Спасибо!