So, why does this cause a memory leak in a multithreaded system? Here’s Chris’ answer:
“If you have an STA thread, you are responsible for pumping it. When your code is in a DLL, the thread is MTA and you don’t need to pump it.
Like you, I assumed that SqlClient was all managed and there is no COM Interop involved. However, I would not be shocked to find out that a COM object is used for some aspect of it. Not only that, but operations like the clipboard, or listening to SystemEvents, and a number of other activities can involve COM objects.
If even a single COM object is created, and if your STA is not pumping, then this can cause the Finalizer thread to become stuck trying to Release that pUnk. Then if SqlClient or something else is creating a bunch of finalizable instances, they will be leaked until the STA thread is pumped.
One way to verify this is to wait until the leak is evident, then break in with a debugger and see what the Finalizer thread is doing. Most likely it is sitting in an OLE32 GetToSTA or similar call. And the STA thread is probably doing something other than pumping. If the debugger shows you the Finalizable instance that is being processed, the mystery will be solved.”