...
Threads ContextClassLoader
Threads spawned by
...
webapps
If a webapp creates a thread, by default its context classloader is set to the one of the parent thread (the thread that created the new thread). In a webapp, this parent thread is one of tomcat worker threads, whose context classloader is set to the webapp classloader when it executes webapp code.
Furthermore, the spawned thread may be executing (or blocked in) some code that involves classes loaded by the webapp, thus preventing the webapp classloader from being collected.
So, if the spawned thread is not properly terminated when the application is stopped, the webapp classloader will leak because of the strong reference held by the spawned thread.
Example :
No Format |
---|
public class LeakingServlet extends HttpServlet {
private Thread leakingThread;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (leakingThread == null) {
synchronized (this) {
if (leakingThread == null) {
leakingThread = new Thread("leakingThread") {
@Override
public void run() {
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
leakingThread.setDaemon(true);
//leakingThread.setContextClassLoader(null);
leakingThread.start();
}
}
}
response.getWriter().println("Hello world!");
}
}
|
Here, when the app is stopped, the webapp classloader is still referenced by the spawned thread both through its context classloader and its current call stack (the anonymous Thread subclass is loaded by the webapp classloader).
When stopping an application, tomcat checks the context classloader of every Thread, and if it is the same as the app being stopped, it logs the following message :
No Format |
---|
Mar 18, 2010 11:13:07 PM org.apache.catalina.core.ApplicationContext log
INFO: HTMLManager: stop: Stopping web application at '/testWeb'
Mar 18, 2010 11:13:07 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [leakingThread] but has failed to stop it. This is very likely to create a memory leak.
|
Now, if we uncomment the line leakingThread.setContextClassLoader(null);
in the above example, tomcat (6.0.24) no longer detect the leak when the application is stopped because the spawned thread context classloader is no longer the webapp's. (the "Find leaks" feature in the manager will report it though)
Threads spawned by classes loaded by the common classloader
TODO : example with the Evictor thread of dbcp
Threads spawned by
...
JRE classes
Child classloaders
static class variables
...
JDBC driver registration
RMI target
Summary matrix
Leak type | Detected by tomcat | Fixed by tomcat | Possible enhancements |
...
References
Related issues
- 48837 - Memory leaks protection does not cure leaks triggered by JSP pages code