3

I have a generic cache used to manage the specified type, however, it's not quite working the way I expected it to. Here is my implementation:

public class GCManagedCache<T> where T : class
{
    private readonly Dictionary<string, WeakReference> _cache = new Dictionary<string, WeakReference>();

    public T this[string key]
    {
        get
        {
            WeakReference weakRef = null;
            if (!_cache.TryGetValue(key, out weakRef))
            {
                return null;
            }

            if (weakRef != null && weakRef.IsAlive)
            {
                return weakRef.Target as T;
            }

            _cache.Remove(key);

            return null;
        }
        set
        {
            _cache[key] = new WeakReference(value);
        }
    }
}

And here is my test:

    [TestMethod]
    public void TestCaching()
    {
        const string KEY = "test";

        GCManagedCache<byte[]> cache = new GCManagedCache<byte[]>();

        var o = new byte[1024];
        cache[KEY] = o;

        var y = cache[KEY];      // <-- seems to keep it alive even though it's nulled out after the next GC call.

        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);

        o = null;
        y = null;

        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);

        var x = cache[KEY];         // <--- returns a valid value when it should be null
        Assert.IsTrue(x == null);
    }

This is the line that is causing the unexpected behavior:

var y = cache[KEY];

With that line in the final assignment :

var x = cache[KEY];

always results in a valid object being returned. If I remove the assignment to "y", then it works as expected.

  • It appears to be a problem with your test runner, running your test in a console program returns `true` for `x == null` with the assignment to `y` in place. – Scott Chamberlain Jan 30 '15 at 14:48
  • 1
    Side note: [`IsAlive`](https://msdn.microsoft.com/en-us/library/system.weakreference.isalive(v=vs.110).aspx): "Because an object could potentially be reclaimed for garbage collection immediately after the `IsAlive` property returns *true*, using this property is not recommended unless you are testing only for a *false* return value." – Damien_The_Unbeliever Jan 30 '15 at 14:54
  • 1
    This may be an issue with code optimization. Does it behave differently in a debug build than it does in a release build? See this related question: http://stackoverflow.com/questions/15205891/garbage-collection-should-have-removed-object-but-weakreference-isalive-still-re – hatchet - done with SOverflow Jan 30 '15 at 14:58

0 Answers0