2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 using System.Collections.Generic;
20 using System.Threading;
22 namespace Mono.Lucene.Net.Util
25 /// <summary>Java's builtin ThreadLocal has a serious flaw:
26 /// it can take an arbitrarily long amount of time to
27 /// dereference the things you had stored in it, even once the
28 /// ThreadLocal instance itself is no longer referenced.
29 /// This is because there is single, master map stored for
30 /// each thread, which all ThreadLocals share, and that
31 /// master map only periodically purges "stale" entries.
33 /// While not technically a memory leak, because eventually
34 /// the memory will be reclaimed, it can take a long time
35 /// and you can easily hit OutOfMemoryError because from the
36 /// GC's standpoint the stale entries are not reclaimaible.
38 /// This class works around that, by only enrolling
39 /// WeakReference values into the ThreadLocal, and
40 /// separately holding a hard reference to each stored
41 /// value. When you call {@link #close}, these hard
42 /// references are cleared and then GC is freely able to
43 /// reclaim space by objects stored in it.
47 public class CloseableThreadLocal
49 private ThreadLocal<WeakReference> t = new ThreadLocal<WeakReference>();
51 private Dictionary<Thread, object> hardRefs = new Dictionary<Thread, object>();
54 public virtual object InitialValue()
59 public virtual object Get()
61 WeakReference weakRef = t.Get();
64 object iv = InitialValue();
79 public virtual void Set(object @object)
82 if (SupportClass.CloseableThreadLocalProfiler.EnableCloseableThreadLocalProfiler == true)
84 lock (SupportClass.CloseableThreadLocalProfiler.Instances)
86 SupportClass.CloseableThreadLocalProfiler.Instances.Add(new WeakReference(@object));
91 t.Set(new WeakReference(@object));
95 //hardRefs[Thread.CurrentThread] = @object;
96 hardRefs.Add(Thread.CurrentThread, @object);
99 foreach (var thread in new List<Thread>(hardRefs.Keys))
102 hardRefs.Remove(thread);
108 public virtual void Close()
110 // Clear the hard refs; then, the only remaining refs to
111 // all values we were storing are weak (unless somewhere
112 // else is still using them) and so GC may reclaim them:
114 // Take care of the current thread right now; others will be
115 // taken care of via the WeakReferences.
124 internal static class CloseableThreadLocalExtensions
126 public static void Set<T>(this ThreadLocal<T> t, T val)
131 public static T Get<T>(this ThreadLocal<T> t)
136 public static void Remove<T>(this ThreadLocal<T> t)
141 public static object Get(this WeakReference w)
148 //// To compile against Framework 2.0
149 //// Uncomment below class
151 public class ThreadLocal<T> : IDisposable
154 static SupportClass.WeakHashTable slots;
158 if (slots == null) slots = new SupportClass.WeakHashTable();
166 slots.Add(this, value);
171 return (T)slots[this];
175 public void Dispose()