Just lost three hours on this, hopefully the story will be useful to someone else too. I’ve been trying to use the WeakReference class for caching. The usage is simple – I have a (singleton) factory object which spits out objects of a certain class, let’s say Widget. At the same time the factory caches the Widget object so that if someone else asks for it, the same copy is returned (based on some criteria). In order not to keep the Widget objects in memory when nobody is referencing it, the factory keeps a WeakReference to a Widget, not a regular (strong) reference to it.

In an isolated (simplified) test case everything worked fine. I would produce one Widget object (thus storing WeakReference to it in a cache) and return it. Then I would make another WeakReference to the same object, then nullify the strong reference, call GC.Collect and test if the second weak reference is null. Like this:

Widget wg = WidgetFactory.GetWidget("Round", 32);
WeakReference wr = new WeakReference(wg);
wg = null;
Thread.Sleep(1000); // wait until Widget is constructed
GC.Collect();
Debug.Assert(!wr.IsAlive);

But wait, what’s that Sleep doing there? Well, my real test was actually failing all the time. I looked, then looked again in my factory code and there was nothing out of the ordinary there. Or at least it seemed like nothing strange was going on.

Turned out that Widget is constructed by asynchronous fetch of data from somewhere. To do this, Widget called ThreadPool.QueueUserWorkItem passing in an anonymous delegate wrapping its method. This was the second strong reference to the Widget, thus the weak reference stayed alive.

Duh.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
0 Comments