How to identify and remove Threads/ThreadLocals initiated from our webapp in Java?
There is no solution to fix all threadlocal leaks in one go.Normally third party libraries using Threadlocal variables have some kind of cleanup API call which can be used to clear their local thread variables.
You have to check for all reported threadlocal leaks and find the correct way of disposing them in the corresponding library. You can do this in your CustomServletContextListener
examples:
log4j (javadoc):
LogManager.shutdown()
jdbc driver: (javadoc):
DriverManager.deregisterDriver(driver);
note: Also check for new versions of your 3rd party libs to check fox fixes concerning memory leaks (and/or thread local leaks).
Solution depends on the library that created these Threads/ThreadLocal-s.Basically you need to call library's cleanup code from your CustomServletContextListener.contextDestroyed() method.
So find what is the library and how to shut it down properly.
You can try this code to remove all ThreadLocal
private void cleanThreadLocals() { try { // Get a reference to the thread locals table of the current thread Thread thread = Thread.currentThread(); Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); Object threadLocalTable = threadLocalsField.get(thread); // Get a reference to the array holding the thread local variables inside the // ThreadLocalMap of the current thread Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap"); Field tableField = threadLocalMapClass.getDeclaredField("table"); tableField.setAccessible(true); Object table = tableField.get(threadLocalTable); // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object // is a reference to the actual ThreadLocal variable Field referentField = Reference.class.getDeclaredField("referent"); referentField.setAccessible(true); for (int i=0; i < Array.getLength(table); i++) { // Each entry in the table array of ThreadLocalMap is an Entry object // representing the thread local reference and its value Object entry = Array.get(table, i); if (entry != null) { // Get a reference to the thread local object and remove it from the table ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry); threadLocal.remove(); } } } catch(Exception e) { // We will tolerate an exception here and just log it throw new IllegalStateException(e); }}