Memory leak in .NET Garbage Collector with System.Transactions.SafeIUnknown
I'm trying to track down a memory leak in an application using ANTS profiler. I tracked it down to the Garbage collector where we have a list of objects System.Transactions.SafeIUnknown that sit there forever in the garbage collector, are in the finalizer queue but never get released.
I can find not documentation what so ever on the System.Transactions.SafeIUnknown nor can I determine what would create or reference this, it's nothing intentional on our par开发者_开发知识库t.
I am hoping someone out there may have some knowledge about this. It's a small leak of 20bytes but when our apps runs for days on end the leak builds up and we have millions of these waiting finalization and it starts to eat up lots and lots of memory.
Anyone any ideas where to go from here?
Follow-up
I've tracked it down to a particular library that is in use. It seems to get left behind after we execute any SQL statements through this particular library. The statemtements are not wrapped in transactions, but they are executed through a rather convuleted loop, of generic types and what currently looks like double-tripple indirection with delegates being passed around for sport and wrapped in closures which can be wrapped in more closures. I'll keep trying to tie it down exactly, my first port of call is to try and see if I can reproduce it using a similar mechanism.
SafeIUnknown is derived from SafeHandle. That's the class that implements the finalizer. It is special, its finalization code runs in a critical execution region (CER). Such kind of code provides an execution guarantee, exceptions are suppressed. The finalizer runs SafeIUnknown.ReleaseHandle(), it makes a call to Marshal.Release() to release the COM interface pointer that's wrapped by SafeIUnknown.
Seeing a lot of these wrappers in the finalization queue indicates that the Marshal.Release() call is throwing an exception. Preventing the wrapper from getting finalized. Finding out exactly why it is throwing an exception is going to be tricky. This is unmanaged code bombing, you'll have few hints available to find out why. The 95% case is heap corruption, a very difficult problem to troubleshoot. Most of all because this probably isn't your code and you don't have any source.
You ought to be able to get a breakpoint in a good unmanaged code debugger (like WinDbug) on the first-chance exception. Getting debugging symbols is essential to make any kind of sense of the stack trace. It will however probably still be a long shot from there. Consider getting help from Microsoft Support. Or something drastic like rebuilding the machine. Good luck with it!
The SafeIUnknown originates from a few methods in System.Transactions, one of which is the TransactionScope
constructors and Dispose method. Calls to these ends up in an internal method on the Transaction
class called JitSafeGetContextTransaction
which further calls into the native Ole32 function CoGetDefaultContext
which returns an instance of the SafeIUnknown
.
This hints that the object in question is related to the internal representation of your transaction context.
Could it be that you are not properly freeing transactions or transaction scopes? If so, perhaps there is some issue with the data provider you're using?
精彩评论