Использование Windbg для поиска утечки памяти в приложении asp.net - PullRequest
2 голосов
/ 19 марта 2019

Описание проблемы

За последние несколько месяцев мы обнаружили проблему в моем онлайн-приложении Asp.net.Приложение работает нормально, но 1 или 2 раза в день оно внезапно завершается сбоем на разных модулях на работающем сервере, но они вообще не являются проблемой в коде и не обнаруживают таких проблем на локальном сервере.

ПослеВ некоторых исследованиях я обнаружил, что у процесса, который запускает мое приложение на IIS на работающем сервере, его память постоянно увеличивается, и когда он достигает определенного уровня, он начинает падать.

Временное решение:

когда мы обнаруживаем такую ​​проблему, мы перезапускаем приложение на IIS.который может завершить этот процесс и начать новый процесс, а затем после того, как это приложение начнет работать.

Через день нам потребуется перезапустить наше приложение в 2 или 3 раза, а в несколько раз больше.

Проблема, которую я нахожу: утечка памяти.

Найдите какое-то решение после некоторого исследования:

  1. создайте файл дампа из моего процесса приложения из диспетчера задач при сбое приложения.

Использование инструмента: Windbg

открыть в инструменте Windbg для анализа.

команда записи

 .load by clr
  dumpheap -stat

показывает тонны ссылок типов данных.Теперь я застрял в этой точке.Я делюсь с вами в разделе изображений.

Вопрос:

1. I am on the right direction in finding memory leaks issue?
2. if my path is right where whats my next step?
3. Windbg tool is good for finding such kind of issue?

Output of dumpheap stack

enter image description here

ссылка на файл дампа для подробного просмотра, я беру этот файл дампа, когда сервер останавливается, чтобы ответить

1 Ответ

0 голосов
/ 20 марта 2019

создать файл дампа из моего процесса приложения из диспетчера задач при сбое приложения

Это не хороший выбор, потому что

  • у тебя мало времени для этого. Это можно сделать только до тех пор, пока отображается диалоговое окно сбоя. Если вы опоздали, приложение пропало.
  • в этом состоянии у вас будут трудности с его отладкой. Вместо исходного исключения будет отображаться точка останова, которая используется ОС для отображения диалогового окна и сбора диагностических данных

Используйте локальные дампы WER, чтобы автоматически создавать аварийный дамп при сбое, вместо того, чтобы делать это вручную. Это гораздо надежнее и дает вам оригинальное исключение. См. Как получить хороший аварийный дамп для .NET

Я нахожусь в правильном направлении в поиске проблемы утечки памяти?

Извините, вы уже не на том пути.

Начиная с !dumpheap -stat не очень хорошая идея. Обычно можно начать с самого низкого уровня, который составляет !address -summary. Он покажет вам, является ли это утечкой управляемой памяти или утечкой собственной памяти. Если это управляемая утечка, вы можете продолжить с !dumpheap -stat

если мой путь правильный, где мой следующий шаг?

Даже если это не правильный путь, неплохо бы узнать, как понять, что вы на неправильном пути. Итак, откуда я знаю?

Глядя на ваш вывод !dumpheap -stat, вы можете увидеть

[...]
111716     12391360 System.String.

Это говорит о том, что есть 110 000 различных строк, использующих 12 МБ памяти. Это также говорит вам, что все остальное занимает менее 12 МБ. Посмотрите на другие размеры, и вы обнаружите, что .NET не является причиной вашего исключения OutOfMemoryException. Они используют менее 50 МБ.

Если бы произошла управляемая утечка, вы бы искали пути, к которым подключены объекты, чтобы сборщик мусора думал, что он не может быть освобожден. Команда !gcroot.

Средство Windbg подходит для поиска подобных проблем?

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

Однажды я написал , как использовать WinDbg для отслеживания .NET OutOfMemoryException . Там вы найдете таблицу, которая дает вам идеи о том, как действовать в различных ситуациях.


В вашем дампе я вижу 2 ТБ <unknown> памяти, которая может быть .NET, но не обязательно должна быть . Тем не менее, эти 2 ТБ, вероятно, являются причиной ООМ, поскольку размер остальных составляет менее 350 МБ.

Поскольку clr находится в списке загруженных модулей, мы можем проверить !dumpheap -stat, как вы это сделали. Но не так много объектов, использующих память.

!eeheap -gc показывает, что есть 8 куч, соответствующих 8 процессорам вашей машины, для параллельной сборки мусора. Самая большая отдельная куча составляет 45 МБ, всего 249 МБ. Это примерно соответствует сумме !dumpheap. вывод: .NET не виновник.

Давайте проверим особые случаи:

  1. Присутствие MSXML
  2. Bitmaps
  3. Звонки на HeapAlloc(), которые настолько велики, что они напрямую переадресовываются на VirtualAlloc().
  4. Прямые звонки на VirtualAlloc()

MSXML отсутствует: lm m msxml* не производит вывод.

Нет растровых изображений: !dumpheap -stat -type Bitmap

Распределение кучи больше 512 кБ: !heap -stat. Вот усеченная часть вывода:

0:000> !heap -stat
_HEAP 0000018720bd0000
     Segments            00000006
         Reserved  bytes 0000000001fca000
         Committed bytes 0000000001bb3000
     VirtAllocBlocks     00000002
         VirtAlloc bytes 00000312cdc4b110
_HEAP 0000018bb0fe0000
     Segments            00000005
         Reserved  bytes 0000000000f0b000
         Committed bytes 0000000000999000
     VirtAllocBlocks     00000001
         VirtAlloc bytes 0000018bb0fe0110

Как видите, в VirtualAlloc есть 3 блока. Размер несколько нереальный:

0:000> ? 00000312cdc4b110
Evaluate expression: 3379296514320 = 00000312`cdc4b110
0:000> ? 0000018bb0fe0110
Evaluate expression: 1699481518352 = 0000018b`b0fe0110

Это будет в общей сложности 3,3 ТБ + 1,7 ТБ = 6 ТБ, а не 2 ТБ. Теперь может случиться так, что это ошибка !address, но 4 ТБ не является общей точкой переполнения.

С помощью !heap -a 0000018720bd0000 вы можете увидеть 2 виртуальных выделения:

Virtual Alloc List:   18720bd0110
    0000018bac70c000: 00960000 [commited 961000, unused 1000] - busy (b), tail fill
    0000018bad07b000: 00960000 [commited 961000, unused 1000] - busy (b), tail fill

А с !heap -a 0000018bb0fe0000 вы можете увидеть третий:

Virtual Alloc List:   18bb0fe0110
    0000018bb1043000: 00400000 [commited 401000, unused 1000] - busy (b), tail fill

Это все относительно небольшие блоки по 4,1 МБ и 9,8 МБ.

Для последней части прямых звонков на VirtualAlloc() вам необходимо вернуться на уровень !address. С !address -f:VAR -c:".echo %1 %3" вы можете увидеть адрес и размер всех <unknown> регионов. Там вы найдете много записей, множество небольших размеров, некоторые из которых могут быть кучами .NET, несколько 2 ГБ и одно действительно большое выделение

2ГБ:

0x18722070000 0x2d11000
0x18724d81000 0x7d2ef000
0x187a2070000 0x2ff4000
0x187a5064000 0x7d00c000
0x18822070000 0x2dfe000
0x18824e6e000 0x7d202000
0x188a2070000 0x2c81000
0x188a4cf1000 0x7d37f000
0x18922070000 0x2d13000
0x18924d83000 0x7d2ed000
0x189a2070000 0x2f5a000
0x189a4fca000 0x7d0a6000
0x18a22070000 0x2c97000
0x18a24d07000 0x7d369000
0x18aa2070000 0x2d0c000
0x18aa4d7c000 0x7d2f4000

Вполне вероятно, что это кучи .NET (зафиксированная часть + зарезервированная часть).

Большой:

0x7df600f57000 0x1ffec56a000

Информация о нем:

0:000> !address 0x7df600f57000 

Usage:                  <unknown>
Base Address:           00007df6`00f57000
End Address:            00007ff5`ed4c1000
Region Size:            000001ff`ec56a000 (   2.000 TB)
State:                  00002000          MEM_RESERVE
Protect:                <info not present at the target>
Type:                   00040000          MEM_MAPPED
Allocation Base:        00007df5`ff340000
Allocation Protect:     00000001          PAGE_NOACCESS

Он выглядит как файл отображения памяти объемом 2 ТБ, который не используется (и, следовательно, зарезервирован).

Я не знаю, что делает ваше приложение. Это действительно то, где мне нужно остановить анализ. Я надеюсь, что это было полезно, и вы можете сделать свои выводы и решить проблему.

...