In relation to my previous question, I need to check whether a component that will be instantiated by Castle Windsor, can be garbage collected after my code has finished using it. I have tried the suggestion in the answers from the previous question, but it does not seem to work as expected, at least for my code. So I would like to write a unit test that tests whether a specific object instance can be garbage collected after some of my code has run.
Is that possible to do in a reliable way ?
EDIT
I currently have the following test based on Paul Stovell's answer, which succeeds:
[TestMethod]
public void ReleaseTest()
{
WindsorContainer container = new WindsorContainer();
container.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
container.AddComponentWithLifestyle<ReleaseTester>(LifestyleType.Transient);
Assert.AreEqual(0, ReleaseTester.refCount);
var weakRef = new WeakReference(container.Resolve<ReleaseTester>());
Assert.AreEqual(1, ReleaseTester.refCount);
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.AreEqual(0, ReleaseTester.refCount, "Component not released");
}
private class ReleaseTester
{
public static int refCount = 0;
public ReleaseTester()
{
refCount++;
}
~ReleaseTester()
{
refCount--;
}
}
Am I right assuming that, based on the test above, I can conclude that Windsor will not leak memory when using the NoTrackingReleasePolicy ?
Perhaps you could hold a WeakReference to it and then check to see that it no longer alive (i.e., !IsAlive) after the tests have completed.
Based on Paul's answer, I created a more reusable Assert method. Since
string
's are copied by value I added an explicit check for them. They can be collected by the garbage collector.The following unit tests show the function is working in some common scenarios.
Due to differences when using the
Release
configuration (I assume compiler optimizations), some of these unit tests would fail ifGC.KeepAlive()
were not to be called.Complete source code (including some of the helper methods used) can be found in my library.
This is not an answer, however you may want to try running your code in both Debug and Release modes (for comparison sake).
In my experience the Debug version of JIT'ed code is made easier to debug and thus may see references stay alive longer (I belive function scope) However, code JITed in Release mode may have the objects ready for collection quickly once it is out of scope and if a Collection happens.
Also not answering your question: :-)
I would be interested in seeing you debug this code using Visual Studio in Interop mode (Managed and Native) and then breaking after displaying a message box or something. Then you can open the Debug->Windows-Immediate and then type
(or you can use Windbg as other's have posted in previous posts)
Thanks, Aaron
This is what I normally do:
NB: There are very, very few times where you should call GC.Collect() in a production application. But testing for leaks is one example of where it's appropriate.
Use dotMemory Unit framework (it's free)