Tengo una aplicación que experimenta una fuga de memoria lenta desde el principio.¿Cómo puedo encontrar el motivo de una cola colgada del finalizador?
Usando ANTS Memory Profiler Veo que toda la memoria filtrada está siendo retenida por la raíz de la cola del finalizador de la GC.
sospecho lo que puede haber sucedido es que el finalizador está en punto muerto a la espera de una cerradura que estén disponibles.
Ninguna de nuestras clases implementan finalizadores explícitos, los evitamos, por regla general, esto me hace pensar el poder de bloqueo en relación con un sistema o una clase de biblioteca.
He usado SOS.dll
para ver el contenido de la cola del finalizador y si lo interpreto correctamente, entonces informa que el primer elemento es una instancia System.Threading.Thread
Sin embargo, no estoy seguro de si el encabezado de la cola realmente representa el objeto actualmente dispuesto o el siguiente objeto a eliminar.
- ¿Hay algún truco que pueda usar para averiguar qué se está finalizando?
- ¿Hay alguna manera de averiguar qué bloqueo está esperando el finalizador?
- ¿Se puede activar alguna depuración adicional para rastrear las acciones del thread del finalizador?
- ¿Qué más puedo ver?
actualización
pila del subproceso finalizador aparece como sigue:
[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
¿Por qué se evitan los finalizadores como regla? La implementación correcta del patrón desechable * requiere * finalizador. – svick
@svick - Una nota en MSDN re. la implementación de IDisposable dice "Deje el finalizador si una clase no posee recursos no administrados" – chillitom
@svick - chillitom es correcto. Citando [Framework Design Guidelines] (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613): "Realmente no desea escribir un finalizador si puede evitarlo". – TrueWill