I am working on an spring MVC project. Project is still under development and I am getting this below warning in STS and also if I deploy war into my local Tomcat 7 server.
warning on console :
ClassLoaderLeakPreventor: Stopping Thread 'Thread[C3P0PooledConnectionPoolManager[identityToken->2ryrk49cntz2wcsrr79v|40b86944]-HelperThread-#2,5,main]' of type com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread running in web app after 5000 ms
WARN : 13:26:22.626 com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:689) - An Error forced the closing of Thread[C3P0PooledConnectionPoolManager[identityToken->2ryrk49cntz2wcsrr79v|40b86944]-HelperThread-#1,5,main]. Will attempt to reconstruct, but this might mean that something bad is happening.
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:758)
at se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor.stopThreads(ClassLoaderLeakPreventor.java:732)
at se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor.contextDestroyed(ClassLoaderLeakPreventor.java:397)
at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4741)
at org.apache.catalina.core.StandardContext$4.run(StandardContext.java:5450)
at java.lang.Thread.run(Thread.java:662)
at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5459)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:225)
at org.apache.catalina.core.ContainerBase.stopInternal(ContainerBase.java:1072)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:225)
at org.apache.catalina.core.ContainerBase.stopInternal(ContainerBase.java:1072)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:225)
at org.apache.catalina.core.StandardService.stopInternal(StandardService.java:502)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:225)
at org.apache.catalina.core.StandardServer.stopInternal(StandardServer.java:748)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:225)
at org.apache.catalina.startup.Catalina.stop(Catalina.java:693)
at org.apache.catalina.startup.Catalina.start(Catalina.java:654)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:303)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:431)
I am not able to trace why this happening. On console I can see this warning continuously printing and tomcat server is in stopping
mode more than 10-12 mins.
We have used class loader leak protection by adding following dependency in pom.xm
<dependency>
<groupId>se.jiderhamn</groupId>
<artifactId>classloader-leak-prevention</artifactId>
<version>1.8.0</version>
</dependency>
Also c3p0
dependency
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2</version>
</dependency>
Why it is saying something bad is happening in warning? Is this a serious issue? How can I stop this?
TL; DR: Upgrade to c3p0 0.9.5.1, then set privilegeSpawnedThreads to true
and contextClassLoaderSource to library
. Make sure that any web-app that creates a c3p0 pool internally closes it on web-app undeploy.
Docs: See c3p0 docs on this issue, here and here
Long version:
Tomcat segregates web-app deployments into dedicated ClassLoaders. On hot redeploy, your web app's code is reloaded into a new ClassLoader, which is how your code changes become visible without restarting the whole JVM.
But old ClassLoaders cannot be garbage collected if Threads refer to objects of classes loaded with those old ClassLoaders.
c3p0 starts up a bunch of Threads every time a PooledDataSource is initialized (when the first Connection is requested). If a web app loaded class provokes the initialization, those Threads may start loading classes with the web-app specific ClassLoader. If those Threads remain alive upon hot-redeploy, they will prevent the garbage collection of the obsoleted ClassLoader and cause a memory leak. (Both the old ClassLoader and the zombie Threads will be unhelpfully retained.) That is the bad thing that is happening in your case. Eventually, after some number of redeploys, you'll see OutOfMemoryErrors
and things will turn flaky.
Fortunately, it is not hard to deal with this. A few suggestions:
No matter what, be sure to scope your Connection pool consistently.
WEB-INF/lib
directory, then be sure that your web app also calls close()
on the pool prior to any undeploy, which will cause the pool's Threads to terminate. The best way to accomplish that is with a ServletContextListener
. Start up your pool in contextInitialized(...)
, and close()
it in contextDestroyed(...)
.lib
directory of the top-level Tomcat installation.In either case, you'll want to upgrade to c3p0-0.9.5 or higher (the current production version is 0.9.5.1), then set the following c3p0 config parameters to take the randomness out of what ClassLoader c3p0-internal Threads come to reference:
true
library
.Hope this helps!