2011-10-09 7 views
9

Ho un'applicazione che presenta una perdita di memoria lenta dalla parola "go".Come posso trovare il motivo per una coda di finalizzatore bloccata?

Utilizzo di Profiler di memoria ANTS Vedo che tutta la memoria trapelata è trattenuta dalla radice GC della coda del finalizzatore.

Sospetto che ciò che potrebbe essere accaduto è che il finalizzatore è bloccato in attesa di una serratura per essere disponibile.

Nessuno dei nostri corsi implementa i finalizzatori espliciti, li evitiamo di solito, questo mi fa pensare che il blocco potrebbe essere correlato a un sistema o una classe di libreria.

Ho usato SOS.dll per dare un'occhiata al contenuto della coda del finalizzatore e se sto interpretando correttamente, allora riporta il primo elemento come un'istanza System.Threading.Thread Tuttavia non sono sicuro se il capo della coda rappresenti effettivamente l'oggetto attualmente disposto o l'oggetto successivo da smaltire.

  • Ci sono trucchi che posso utilizzare per scoprire cosa viene finalizzato?
  • C'è un modo per scoprire su quale blocco è attivo il thread del finalizzatore?
  • È possibile attivare eventuali debug aggiuntivi per tracciare le azioni del thread di finalizzazione?
  • Cos'altro posso guardare?

Aggiornamento

stack del thread finalizzatori appare come segue:

ntdll.dll!_ZwWaitForSingle[email protected]() + 0x15 bytes 
[email protected]() + 0x15 bytes 
[email protected]() + 0x15 bytes  

[email protected]() + 0x43 bytes  
[email protected]() + 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  
[email protected]@4() + 0xe bytes  
rpcrt4.dll!_NdrClientCall2() + 0x144 bytes 
[email protected]() + 0x7a bytes  
[email protected]() + 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 
[email protected]@12() + 0x12 bytes  
[email protected]() + 0x27 bytes  
[email protected]() + 0x1b bytes  
+1

Perché stai evitando i finalizzatori di norma? L'implementazione corretta del modello monouso * richiede * finalizzatore. – svick

+2

@svick - Una nota su MSDN re. implementare IDisposable dice "Lascia fuori completamente il finalizzatore se una classe non possiede risorse non gestite" – chillitom

+1

@svick - chillitom è corretto. Citando [Framework Design Guidelines] (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613): "Davvero non vuoi scrivere un finalizzatore se puoi aiutarlo." – TrueWill

risposta

9

Sembra a me si stanno avendo un problema con un server COM. Lo stack di chiamate mostra che sta tentando di effettuare la chiamata IUnknown :: Release() su un oggetto COM a thread singolo. La chiamata ReleaseRCWListInCorrectCtx() la disabilita, _NtUserPostMessage @ 16() è la chiamata che effettua il marshalling della richiesta allo STA che possiede l'oggetto COM.

La causa tipica è la creazione di oggetti COM e non il pompaggio di un loop di messaggi. Un requisito indispensabile per i thread STA. Lo eviti creando sul thread dell'interfaccia utente principale e non bloccandolo mai.

+1

spot on, il metodo principale del programma è stato contrassegnato [STAThread] per adattarsi a una modalità GUI, ma normalmente funzionerebbe come un servizio Windows. Di recente è stato introdotto un componente COM, probabilmente candidato a un timer. Come hai previsto senza thread dell'interfaccia utente, il finalizzatore del servizio si blocca. – chillitom

+1

FYI, Se il tuo thread principale sta facendo qualcosa come 'Console.ReadLine', ma vuoi che stia pompando dei messaggi, puoi creare un nuovo Thread per fare il readline, e quindi usare' .Join' su di esso dal tuo Main filo. Internamente 'Thread.Join' quando viene chiamato su un thread STA pompa messaggi COM, che dovrebbero consentire agli oggetti di usarlo. –

Problemi correlati