jeudi 5 mars 2015

C# mysterious array keeps reference to object in unit tests

I just observed a really weird behavior in Visual Studio 2013 Update 4. Consider the following xunit.net test:



[Fact]
public void TestTargetMustNotHoldAReferenceToItemsAfterCallingClear()
{
var item = new MarkedType();
var weakReferenceToItem = new WeakReference<MarkedType>(item);
var testTarget = new ListBuilder<MarkedType>().WithItems(item)
.Build();

testTarget.Clear();

item = null;
GC.Collect();
MarkedType retrievedItem = null;
Assert.False(weakReferenceToItem.TryGetTarget(out retrievedItem));
Assert.Null(retrievedItem);
}

public class MarkedType { }


In it, I want to check that my own List<T> implementation does not hold references to objects on the heap after I call Clear on it. Therefore I set item to null after the call to Clear and let the Garbage Collector run so that it can deallocate the MarkedType instance. Afterwards I check with a weak reference that the instance is really gone.


Here is the weird thing: this test does not pass in Debug mode in VS 2013 Update 4 with xunit.net v2.0.0 prerelease because WeakReference.TryGetTarget returns true. However, if I switch to Release mode, this test passes. I also ran this test in VS 2015 CTP6 and there it passes in both configurations, Debug and Release.


I then created two memory dumps (one before the garbage collector run, one after) to figure out what object keeps item in memory and I found an object array that is not listed in my test:


Marked Type Path To Root


My actual questions are: where does this object array come from? Why isn't it present in Release mode (or VS 2015)? Can I somehow disable or circumvent it?


If you want to play around with the source code, it is available on github (please use the FailingReferenceTest branch): http://ift.tt/1H1TKMo


Aucun commentaire:

Enregistrer un commentaire