Skip to content

Instantly share code, notes, and snippets.

@DiveInto
Created November 12, 2012 05:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DiveInto/4057644 to your computer and use it in GitHub Desktop.
Save DiveInto/4057644 to your computer and use it in GitHub Desktop.
try leak memory according to http://stackoverflow.com/a/6471947/404145
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class MLeaks {
static byte[] m = new byte[1024 * 1024];
static ThreadLocal<MLeaks> tLocal = new ThreadLocal<MLeaks>(){
@Override
protected MLeaks initialValue()
{
return new MLeaks();
}
};
public static void main(String[] args){
while(true){
Thread thread = new Thread(){
public void run() {
try {
URLClassLoader cl = new URLClassLoader(new URL[]{new URL("file:/path-to/MLeaks/bin/")});
System.out.println(cl.toString());
Class<MLeaks> tmpClass = (Class<MLeaks>) cl.loadClass(MLeaks.class.getName());
tmpClass = null;
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
}
@dpryden
Copy link

dpryden commented Nov 16, 2012

It's true, if you only subclass ThreadLocal and never actually assign a value into the the thread local storage, then you're not leaking. In my experience, for these kinds of use cases (a thread local in a framework), the ThreadLocal object is almost always instantiated directly instead of being subclassed.

As it turns out, a lot of existing code follows this kind of pattern. For example, most Java servlet containers create a bunch of long running threads which are used to handle requests, then load each application in its own ClassLoader. When you update the application (e.g. by replacing the WAR file), the old ClassLoader is discarded and a new one is created. All of this works fine, unless you also have a framework in place that uses ThreadLocals. As it turns out, lots of popular frameworks use thread local storage (including many Java web application frameworks), and many frameworks compound the problem by creating their own ClassLoaders to do runtime bytecode manipulation (Hibernate and many AOP frameworks do this). A large application can easily pull in a dozen or so different large libraries and frameworks, and it can be very difficult to determine exactly where you have the one dangling reference that is keeping your entire application in memory.

The common way that this problem manifests is on a development/debugging server. For example, on a previous project, I would develop our web application (which used Stripes, Guice, Hibernate, and a handful of other big libraries) on a local Tomcat server. Throughout the day I would frequently redeploy the application to my local server, and I was guaranteed to to have to restart my local server at least once every few hours because the PermGen would fill up and the server would crash.

The point of my answer over at StackOverflow was that this is a true memory leak: once the ClassLoader is discarded, there's no way to retrieve the ThreadLocal instance anymore, and so short of killing the Thread (and maybe not even then) there is no way to release the memory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment