I\'m using Visual Studio 2010 to target .NET 4.0 Client Profile. I have a C# class to detect when a given process starts/terminates. For this the class uses a ManagementEven
This issue also causes MS Unit Test Framework to fail and hang forever at the end of running all tests (under Visual Studio 2015, update 3). Unfortunately the bug still persists as I am writing this. In my case the following code is leaking:
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
....
}
And what Test Framework is complaining about is about a thread not being shutdown:
System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. This can happen if the test(s) started a thread but did not stop it. Make sure that all the threads started by the test(s) are stopped before completion.
And I managed to get around it by executing the code in another thread (therefore, after the starter thread exits, hopefully all other threads spawned in it are closed and resources are freed appropriately):
Thread searcherThread = new Thread(new ThreadStart(() =>
{
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
....
}
}));
searcherThread.Start();
searcherThread.Join();
I am not advocating that this is the solution to the problem (as a matter of fact, spawning a thread just for this call is a horrible idea), but at least I can run tests again without needing to restart Visual Studio every time it hangs.
We are seeing similar problem,
calling GC.WaitForPendingFinalizers() once is enough to fix the leak
though I am aware it is not a solution, just a workaround the bug
At first glance, there appears to be a bug in ManagementBaseObject
.
Here's the Dispose()
method from ManagementBaseObject
:
public new void Dispose()
{
if (_wbemObject != null)
{
_wbemObject.Dispose();
_wbemObject = null;
}
base.Dispose();
GC.SuppressFinalize(this);
}
Notice that it is declared as new
. Also notice that when the using
statement calls Dispose
, it does so with the explicit interface implementation. Thus the parent Component.Dispose()
method is called, and _wbemObject.Dispose()
is never called. ManagementBaseObject.Dispose()
should not be declared as new
here. Don't believe me? Here's a comment from Component.cs
, right above it's Dispose(bool)
method:
/// <para>
/// For base classes, you should never override the Finalier (~Class in C#)
/// or the Dispose method that takes no arguments, rather you should
/// always override the Dispose method that takes a bool.
/// </para>
/// <code>
/// protected override void Dispose(bool disposing) {
/// if (disposing) {
/// if (myobject != null) {
/// myobject.Dispose();
/// myobject = null;
/// }
/// }
/// if (myhandle != IntPtr.Zero) {
/// NativeMethods.Release(myhandle);
/// myhandle = IntPtr.Zero;
/// }
/// base.Dispose(disposing);
/// }
Since here the using
statement calls the explicit IDisposable.Dispose
method, the new
Dispose never gets called.
EDIT
Normally I would not assume that something like this a bug, but since using new
for Dispose
is usually bad practice (especially since ManagementBaseObject
is not sealed), and since there is no comment explaining the use of new
, I think this is a bug.
I could not find a Microsoft Connect entry for this issue, so I made one. Feel free to upvote if you can reproduce or if this has affected you.