Объект не собирает мусор, но не содержит никаких gcroots
Запуск в колючую проблему с нашим веб-приложением здесь. (Asp.net 2.0 Win server 2008)
Наше использование памяти для веб-сайта растет и растет, хотя я ожидаю, что он останется на довольно статическом уровне. (У нас есть небольшой объем данных, которые сохраняются в состоянии).
Чтобы узнать, в чем проблема, я запустил System.GC.Collect(); несколько раз, взял дамп памяти, а затем загрузил этот дамп памяти в WinDbg.
Когда я делаю DumpHeap -Stat, я получаю чрезмерно большое количество на конкретном типе, висящем в памяти.
0000064280580b40 713471 79908752 PaymentOption
поэтому, делая DumpHeap -MT для этого типа, я получаю стек ссылок на объекты. Выбрав случайное число из них, я делаю a! Gcroot, и команда возвращается, сообщая, что ссылки на нее не поддерживаются.
Для меня это точно, когда GC должен собирать эти предметы, но по какой-то причине они остались незаметными.
Может ли кто-нибудь дать объяснение, что может произойти?
Ответы
Ответ 1
Вы можете попробовать использовать sosex.dll в Windbg, который является расширением, написанным для помощи в отладке .NET. Существует команда с именем! Refs, которая похожа на! Gcroot, так как она покажет вам все объекты, ссылающиеся на объект, плюс отобразит все объекты, к которым он ссылается.
В примере на веб-сайте автора, refs используется против объекта, и результат выглядит следующим образом:
0:000> !refs 0000000080000db8
Objects referenced by 0000000080000db8 (System.Threading.Mutex):
0000000080000ef0 32 Microsoft.Win32.SafeHandles.SafeWaitHandle
Objects referencing 0000000080000db8 (System.Threading.Mutex):
0000000080000e08 72 System.Threading.Mutex+<>c__DisplayClass3
0000000080000e50 64 System.Runtime.CompilerServices.RuntimeHelpers+CleanupCode
Ответ 2
Немного вещей:
- GC.Collect не поможет вам отлаживать. Сборщик мусора уже вызывается: если бы какие-либо объекты были доступны для коллекции, это уже было бы.
- Свободная память на сервере - это потерянная память. Вы уверены, что память "просочилась", или это только то, что платформа решает, что она может хранить больше вещей в memroy или поддерживать больше памяти для более быстрого доступа? В этом случае я подозреваю, что вы утечка памяти, но это что-то, что нужно дважды проверить.
- Звучит так, как будто вы не ожидаете, что ссылается на объекты PaymentOption. Может быть, статическая коллекция где-то? Или отдельный поток?
Ответ 3
Предоставляет ли PaymentObject финализатор? Он вызывает объект STA COM?
Мне было бы интересно увидеть результат! finalizequeue, чтобы увидеть, будет ли подсчет объектов, которые появляются в куче, примерно столько, сколько может ожидать до финализации. Результат должен выглядеть примерно так:
generation 0 has 57 finalizable objects (0409b5cc->0409b6b0)
generation 1 has 55 finalizable objects (0409b4f0->0409b5cc)
generation 2 has 0 finalizable objects (0409b4f0->0409b4f0)
Ready for finalization 0 objects (0409b6b0->0409b6b0)
Если количество объектов Готово для завершения продолжает расти, и ваши определенные коллекции мусора происходят (подтвердите с помощью счетчиков perfmon), то это может быть заблокированный поток финализатора. Возможно, вам понадобится сделать несколько снимков за всю жизнь процесса (до повторного использования) для подтверждения. Обычно я полагаюсь на магическое число из трех, если сайт находится под какой-то нагрузкой.
Ошибка в финализаторе может блокировать поток финализатора и предотвращать сбор объектов.
Если объект PaymentOption вызывает устаревший объект STA COM, то эта статья Исключения ASP.NET Hang и OutOfMemory, вызванные компонентами STA, могут указывать в правильном направлении.
Ответ 4
Не без дополнительной информации о вашем приложении. Но мы столкнулись с некоторыми неприятными проблемами памяти давным-давно. Используете ли вы кеширование ASP.NET? Как Раймонд Чен любит говорить, "бедная стратегия кэширования неизмерима от утечки памяти".
Посмотрите еще один инструмент - CLRProfiler.exe - он поможет вам пересечь деревья ссылок на объекты, чтобы увидеть, где ваши корни. Это также хорошо: текст ссылки
Вы слышали это раньше - если у вас есть GC.Collect, что-то не так.
Ответ 5
Является ли объект PaymentOption, созданный в асинхронном процессе, случайно? Я что-то помню, если вы не вызываете EndInvoke, вы можете получить такие проблемы.
Ответ 6
Я сам сам изучал ту же проблему и спрашивал, почему объекты, которые не имеют ссылок, не собираются.
Объекты размером более 85 000 байт хранятся в кучке большого объекта, из которой память освобождается реже.
http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
Единый PaymentOption может быть не таким большим, но содержатся ли они в коллекциях или они основаны на чем-то вроде DataSet? Вы должны выбрать несколько экземпляров PaymentOption/collection/DataSet, а затем использовать команду sos! Objsize, чтобы увидеть большие.
К сожалению, это не отвечает на вопрос. Мне нравится думать, что я могу доверять платформе .net, чтобы заботиться о выпуске неиспользуемой памяти всякий раз, когда это необходимо. Однако я вижу, что большая часть памяти используется рабочим процессом, в котором выполняется приложение, на которое я смотрю, даже когда память выглядит довольно жестко на сервере.
Ответ 7
FYI, SOS в .NET 4 поддерживает несколько новых команд, которые могут быть полезны, а именно !gcwhere
(найти генерацию возражения; sosex gcgen) и !findroots
(делает то, что он говорит на олове; sosex! рефов)
Оба документа задокументированы в документации SOS и упомянутых в Tess Феррандез.