I was surprised to witness the Java Executor behavior – which caused “java.lang.OutOfMemoryError: unable to create new native thread” in our application. I would like to share my surprise (i.e. problem) and resolution to it.
In order to explain the problem better, I created the following example:
Above program creates 5 workers threads in the runJobs() method and executes 10 DummyJobs in parallel. In order to do so, it uses ThreadPoolExecutor.
In the “runJobs()” method, one would expect ThreadPoolExecutor instance & the worker threads created by that executor would be ready for garbage collection when:
1. “runJobs()” method is completed. As ‘executor’ is a local variable, it should be made available for garbage collection after the execution of the method. As variable has become out of scope.
2. All jobs that were dropped to the Executor were executed.
However surprisingly – even though both of the conditions are meet, still worker threads in the ThreadPoolExecutor instance aren’t getting garbage collected. Whenever “runJobs()” method is called, 5 new worker threads gets created and remains in the memory. If “runJobs()” is called few hundred times, several hundreds of worker threads are created. This causes memory leak in the application.
How to fix this problem?
On line number 37, one would need to invoke “shutdown()” API. So that all the worker threads would be explicitly destroyed after execution of the jobs. So revised runJobs() method would look like:
What triggers this Memory Leak?
Apparently worker threads were put on to wait state by the Executor. Following is the excerpt from the thread dump of the program. Excerpt shows the stack trace of one of the worker thread in the Executor.
You can see the line “at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)". This will park the threads thus making them not to die down. Only when shutdown() API is invoked it would unpark the threads and they would die down.
Your solution goes into the right direction, but is deficient. Cleanup should always be done in a finally-block:
I'm curious what caused you to debug this issue though. Typically you only create one thread pool per application, and resource leaks that occur because you didn't shut down the executor service shouldn't have any real effect because you're terminating the application anyway. So either:
1) You're writing an application container, which is unlikely.
2) You're creating thread pools in places where you really shouldn't be creating thread pools in the first place. Use dependency injection instead.
And to amplify on Stephan's advice, remember that you should absolutely never spawn threads either directly or indirectly from an webapp server's service request handlers (servlets and their downstream logic). Or within EJBs.
Doing so not only violates the JEE specs, but also means that you could unpredictably corrupt the entire appserver at random times.
It's common to see Tomcat log warnings about leaked resources when it shuts down. Tomcat handles most of such problems safely, but the warnings should be heeded and the problems fixed.
In the wider world, a JVM cannot shut down until all of its threads have terminated. If that isn't done, the shutdown will "hang" and the JVM process must be forcibly terminated by the OS.
Sometimes the only way things ever got fixed is because people became uncomfortable.
Water! People swim in water! Even tiny ads swim in water:
free, earth-friendly heat - a kickstarter for putting coin in your pocket while saving the earth