问题
I have an application that experiences a slow memory leak from the word go.
Using ANTS Memory Profiler I can see that all of the leaked memory is being held by the finalizer queue's GC root.
I suspect what may have happened is that the finalizer is deadlocked waiting on a lock to become available.
None of our classes implement explicit finalizers, we avoid them as a rule, this makes me think the lock might related to a system or library class.
I've used SOS.dll
to take a look at the contents of the finalizer queue and if I am interpreting it correctly then it reports the first item to be an instance System.Threading.Thread
However I am unsure if the head of the queue actually represents the currently being disposed object or the next object to be disposed.
- Are there any tricks I can use to find out what is being finalized?
- Is there a way I can find out what lock the finalizer thread is waiting on?
- Can any extra debugging be turned on to trace the finalizer thread's actions?
- What else can I look at?
Update
The finalizer thread's stack appears as follows:
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:
Looks to me you are having a problem with a COM server. The call stack shows it is trying to make the IUnknown::Release() call on a single-threaded COM object. The ReleaseRCWListInCorrectCtx() call sets it off, the _NtUserPostMessage@16() is the call that marshals the request to the STA that owns the COM object.
The typical cause is creating COM objects and not pumping a message loop. A hard requirement for STA threads. You avoid it by creating them on the main UI thread and never blocking it.
来源:https://stackoverflow.com/questions/7704805/how-can-i-find-the-reason-for-a-hung-finalizer-queue