...
But it does not give any clue about what caused the leak, we would need to make a heapdump and analyse it with some tool like Eclipse MAT.
ThreadLocal pseudo-leak
Suppose we have the same MyCounter
class as above (in the webapp) and the following servlet :
No Format |
---|
public class LeakingServlet extends HttpServlet {
private ThreadLocal<MyCounter> myThreadLocal = new ThreadLocal<MyCounter>();
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
MyCounter counter = myThreadLocal.get();
if (counter == null) {
counter = new MyCounter();
myThreadLocal.set(counter);
}
response.getWriter().println(
"The current thread served this servlet " + counter.getCount()
+ " times");
counter.increment();
}
@Override
public void destroy() {
super.destroy();
// normally not needed, just to make my point
myThreadLocal = null;
}
}
|
Notice that the ThreadLocal
instance is referenced through an instance variable, not a static one.
Sun's implementation of ThreadLocal
(and WeakHashMap
) too is such that ThreadLocalMap
entries whose key is GCed are not immediately removed. (The key is a weak reference to the ThreadLocal
instance, see java.lang.ThreadLocal.ThreadLocalMap.Entry<T> in JDK 5/6
. And there's no daemon thread waiting on a ReferenceQueue
). Instead, it's only during subsequent uses of ThreadLocal
features that each Thread removes the abandoned ThreadLocalMap.Entry
entries (see ThreadLocalMap.expungeStaleEntries()
.
If many threads were used to serve our leaking webapp, but after we stop it only a couple of threads are enough to serve other webapps, one could have some threads that are no longer used, waiting for some work. Since those threads are blocked, they have no interaction with their ThreadLocalMap
(i.e. there's no ThreadLocal
value bound to them or removed), so that there's no opportunity to expungeStaleEntries()
.
Tomcat 6.0.24 "speeds up" the removal of stale entries (and thus fixes the pseudo-leak), by calling expungeStaleEntries()
for each thread that has some stale entries.
Threads ContextClassLoader
...