In short, any time I create or use a socket inside a worker thread, that Thread object instance will never be garbage collected. The socket does not need to be connected or bound, it doesn't matter whether I close the socket or not, and it doesn't matter whether I create the Socket object inside the thread or not. As I said, it's nasty.
I initially encountered this memory leak using httpclient (which creates a worker thread for every connect() call), but it is very easy to reproduce with a small amount of stand-alone code. I'm running this test on Windows, and I encounter this memory leak using the latest 1.5 and 1.6 JDK's. I'm using the NetBeans 5.5 profiler to verify which objects are not being freed.
Here's how to reproduce it with an unbound socket created inside a worker thread:
public class Test {
public static class TestRun extends Thread {
public void run() {
new Socket();
}
}
public static void main(String[] strArgs) throws Exception {
for(;;) {
(new TestRun()).start();
Thread.sleep(10);
}
}
}
Here's how to reproduce it with a socket created outside the thread and used inside the worker thread:
public class Test {
public static class TestRun extends Thread {
Socket s;
public TestRun(Socket s) { this.s = s; }
public void run() {
try {
s.bind(new InetSocketAddress(0));
s.close();
} catch(Exception e) {}
}
}
public static void main(String[] strArgs) throws Exception {
for(;;) {
(new TestRun(new Socket())).start();
Thread.sleep(10);
}
}
}
Here's how to reproduce it implementing Runnable instead of extending Thread:
public class Test {
public static class TestRun implements Runnable {
public void run() {
Socket s = new Socket();
try { s.close(); } catch(Exception e) {}
}
}
public static void main(String[] strArgs) throws Exception {
for(;;) {
(new Thread(new TestRun())).start();
Thread.sleep(10);
}
}
}
I've played with this a lot, and no matter what I do the Thread instance leaks if I create/use a socket inside it. The Socket instance gets cleaned up properly, as well as the TestRun instance when it's implementing Runnable, but the Thread instance never gets cleaned up. I can't see anything that would be holding a reference to it, so I can only imagine it's a problem with the JVM.
Please let me know if you can help me out with this,
Sean