Как я могу найти причину зависания очереди финализатора? - PullRequest
9 голосов
/ 09 октября 2011

У меня есть приложение, которое испытывает медленную утечку памяти с самого начала.

Использование ANTS Memory Profiler Я вижу, что вся утечка памяти удерживается корнем GC очереди финализатора.

Я подозреваю, что, возможно, произошло то, что финализатор заблокирован в ожидании блокировки.

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

Я использовал SOS.dll, чтобы взглянуть на содержимое очереди финализатора, и если я правильно его интерпретирую, он сообщает, что первый элемент является экземпляром System.Threading.Thread Однако я не уверен, что глава Очередь фактически представляет текущий объект или следующий объект, который должен быть удален.

  • Есть ли уловки, которые я могу использовать, чтобы узнать, что завершается?
  • Есть ли способ узнать, какую блокировку ожидает поток финализатора?
  • Можно ли включить дополнительную отладку для отслеживания действий потока финализатора?
  • На что еще можно посмотреть?

Обновление

Стек потока финализатора выглядит следующим образом:

ntdll.dll!_ZwWaitForSingleObject@12()  + 0x15 bytes  
ntdll.dll!_ZwWaitForSingleObject@12()  + 0x15 bytes  
user32.dll!_NtUserPostMessage@16()  + 0x15 bytes     

kernel32.dll!_WaitForSingleObjectExImplementation@12()  + 0x43 bytes     
kernel32.dll!_WaitForSingleObject@8()  + 0x12 bytes  
ole32.dll!GetToSTA()  + 0x72 bytes   

ole32.dll!CRpcChannelBuffer::SwitchAptAndDispatchCall()  - 0x1939 bytes  
ole32.dll!CRpcChannelBuffer::SendReceive2()  + 0xa6 bytes    
ole32.dll!CAptRpcChnl::SendReceive()  + 0x5b7 bytes  
ole32.dll!CCtxComChnl::SendReceive()  - 0x14b97 bytes    
ole32.dll!NdrExtpProxySendReceive()  + 0x43 bytes    
rpcrt4.dll!@NdrpProxySendReceive@4()  + 0xe bytes    
rpcrt4.dll!_NdrClientCall2()  + 0x144 bytes  
ole32.dll!_ObjectStublessClient@8()  + 0x7a bytes    
ole32.dll!_ObjectStubless@0()  + 0xf bytes   

ole32.dll!CObjectContext::InternalContextCallback()  - 0x511f bytes  
ole32.dll!CObjectContext::ContextCallback()  + 0x8f bytes    
clr.dll!CtxEntry::EnterContext()  + 0x119 bytes  

clr.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx()  + 0x2bb bytes  

clr.dll!RCWCleanupList::CleanupAllWrappers()  - 0x20fb0 bytes    
clr.dll!SyncBlockCache::CleanupSyncBlocks()  + 0x1ec6 bytes  
clr.dll!Thread::DoExtraWorkForFinalizer()  + 0x411b5 bytes   

clr.dll!WKS::GCHeap::FinalizerThreadWorker()  + 0x8b bytes   
clr.dll!Thread::DoExtraWorkForFinalizer()  + 0xb6e76 bytes   
clr.dll!Thread::ShouldChangeAbortToUnload()  - 0x5f8 bytes   
clr.dll!Thread::ShouldChangeAbortToUnload()  - 0x53d bytes   
clr.dll!ManagedThreadBase_NoADTransition()  + 0x35 bytes     
clr.dll!ManagedThreadBase::FinalizerBase()  + 0xf bytes  
clr.dll!WKS::GCHeap::FinalizerThreadStart()  + 0xfb bytes    
clr.dll!Thread::intermediateThreadProc()  + 0x48 bytes   
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes     
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes    
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes     

1 Ответ

10 голосов
/ 09 октября 2011

Мне кажется, у вас проблема с COM-сервером. Стек вызовов показывает, что он пытается выполнить вызов IUnknown :: Release () для однопоточного COM-объекта. Вызов ReleaseRCWListInCorrectCtx () устанавливает это значение, _NtUserPostMessage @ 16 () - это вызов, который направляет запрос в STA, которая владеет COM-объектом.

Типичная причина - создание объектов COM, а не прокачка цикла сообщений. Жесткое требование к нитям STA. Вы избегаете этого, создавая их в основном потоке пользовательского интерфейса и никогда не блокируя его.

...