Wrong answer #1: Your own ThreadLocal
Originally posted at 12/15/2010
Well, one way we can use to solve the problem is by introducing a finalizer, like so:
public class CloseableThreadLocal { [ThreadStatic] private static Dictionary<object, object> slots; public static Dictionary<object, object> Slots { get { return slots ?? (slots = new Dictionary<object, object>()); } } public /*protected internal*/ virtual Object InitialValue() { return null; } public virtual Object Get() { object val; if (Slots.TryGetValue(this, out val)) { return val; } val = InitialValue(); Set(val); return val; } public virtual void Set(object val) { Slots[this] = val; } public virtual void Close() { GC.SuppressFinalize(this); if (slots != null)// intentionally using the field here, to avoid creating the instance slots.Remove(this); } ~CloseableThreadLocal() { Close(); } }
But this will not actually work, executing this code shows that we still have a memory leak:
internal class Program { private static void Main(string[] args) { UseThreadLocal(); GC.Collect(int.MaxValue); GC.WaitForPendingFinalizers(); Console.WriteLine(CloseableThreadLocal.slots.Count); } private static void UseThreadLocal() { var tl = new CloseableThreadLocal(); tl.Set("hello there"); Console.WriteLine(tl.Get()); } }
Why? And how can we fix this?

Comments
Comment preview