Фрагментация памяти?

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

Во время нагрузочных тестов мы видим, что использование памяти растет до точки перезапуска приложения. Это приложение ASP.NET MVC 4 на 64-битной машине. Я не участвовал в написании этого. Меня просто попросили попробовать проанализировать дампы памяти.

Итак, во время последнего нагрузочного теста мы создали 3 дампа памяти (ниже их размеров и общего размера кучи GC, выводимого из eeheap -gc):

  1. 1.70GB, 292MB
  2. 2.03GB, 337MB
  3. 2.55GB, 347MB

Итак, как видите, управляемая куча не растет так сильно, как файлы дампа. Когда я делаю dumpheap -stat, я вижу, что больше всего места используется бесплатными объектами (ниже для каждого файла дампа)

  1. 147MB
  2. 145MB
  3. 213MB
Fragmented blocks larger than 0.5 MB:
            Addr     Size      Followed by
000000bcc668e0a8    0.7MB 000000bcc6738650 System.Object[]
000000bcc6949f88    4.4MB 000000bcc6dab820 System.Collections.Specialized.NameObjectCollectionBase+NameObjectEntry
000000bd4626c4b8    0.7MB 000000bd463165f8 System.Byte[]
000000bd463fcc48   51.5MB 000000bd4977baf0 System.Threading.ThreadStart
000000be463600c8    0.7MB 000000be464108f0 Free
000000bec67e50e0    1.1MB 000000bec690b020 System.Collections.Generic.List`1[[OurType, ANotherOurType]]
000000bec690b0b8    3.2MB 000000bec6c3b170 System.Byte[]
000000bfc6605e00    1.0MB 000000bfc6710190 Free
000000bfc6743c58   32.8MB 000000bfc8806fe8 System.Threading.ExecutionContext
000000c046200580    1.0MB 000000c0462ff2a0 SomeOurType
000000c0463a1270    3.6MB 000000c046732ac0 Microsoft.Win32.SafeHandles.SafeCapiKeyHandle

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

Приложение использует две внешние библиотеки. Один для создания PDF-файлов, а другой - для создания файлов со штрих-кодом. Библиотека штрих-кода генерирует исключение AccessViolationException (примерно 70 раз из 2200 попыток). Выбрасывается с этой трассировкой стека

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at System.Drawing.SafeNativeMethods.Gdip.IntGdipDeleteGraphics(HandleRef graphics)
   at System.Drawing.Graphics.Dispose(Boolean disposing)
   at System.Drawing.Graphics.Dispose()
   at Lesnikowski.Barcode.BaseBarcode.Render()
   at Lesnikowski.Barcode.BaseBarcode.Save(Stream stream, ImageType imageType)

Я читал, что фрагментация памяти часто вызывается закреплением памяти, но это вывод! Gchandles

Handles:
    Strong Handles:       154
    Pinned Handles:       23
    Ref Count Handles:    2
    Weak Long Handles:    1794
    Weak Short Handles:   74
    SizedRef Handles:     17
    Dependent Handles:    1

Не знаю, что еще можно проверить. У нас проблема фрагментации памяти? Вы можете указать мне какое-нибудь направление?

Изменить: я прикрепляю счетчики производительности, собранные во время нагрузочного теста. Странно, потому что он показывает много закрепленных объектов, но! Gchandles их не показывает.

введите описание изображения здесь

red line   - user load
green line - bytes in all heaps
blue line  - pinned objects

Edit2: добавлены фрагментированные блоки размером более 0,5 МБ: вывод из! Dumpheap -stat


person Piotr Perak    schedule 13.08.2013    source источник
comment
Фрагментация памяти может вызвать OOM; однако это выглядит как обычная ошибка BCL - это не должно быть такой ошибкой, фрагментированной или нет.   -  person Marc Gravell    schedule 13.08.2013
comment
Вы имеете в виду исключения AccessViolationExceptions? Это может быть ошибка BCL или нашей библиотеки BarCode. Но не уверен, что это как-то связано с ростом дампа памяти.   -  person Piotr Perak    schedule 13.08.2013


Ответы (1)


Вы должны использовать !address -summary, чтобы получить представление об использовании виртуальной памяти в этом процессе. Несмотря на то, что кажется, что есть некоторая фрагментация кучи, очень вероятно, что в вашем процессе есть дополнительный тяжелый потребитель памяти. Это может быть куча Win32, стеки потоков, сборки, которые вы загружаете динамически, и так далее.

В этом случае для каждого типа утечки вам придется придерживаться немного другого подхода. Для проверки кучи Win32 следует использовать варианты команды !heap - !heap -stat, !heap -s -h 0. В случае проблем с загрузкой сборок вам следует посмотреть на кучу загрузчика с !eeheap -loader, а затем проверить различные домены приложений с !dumpdomain, чтобы увидеть, какие сборки вы загружаете. Это всего лишь несколько примеров - вам нужно будет предоставить более подробную информацию о вашей ситуации.

person Sasha Goldshtein    schedule 21.08.2013
comment
Спасибо. Думаю, я уже нашел «утечку памяти». Это фрагментация LOH. Не успел обновить вопрос / дать ответ на свой вопрос. - person Piotr Perak; 22.08.2013
comment
@PiotrPerak, не могли бы вы указать мне на некоторые счетчики производительности, которые могут помочь обнаружить происходящую фрагментацию? - person user3004790; 15.04.2021