Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tomcat Wiki" for change 
notification.

The "MemoryLeakProtection" page has been changed by SylvainLaurent.
http://wiki.apache.org/tomcat/MemoryLeakProtection?action=diff&rev1=6&rev2=7

--------------------------------------------------

  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 ===
+ Suppose, we have the [[http://commons.apache.org/pool/|Commons Pool]] library 
in the classpath of the server (e.g. the jar is in tomcat/lib), and the 
following servlet :
+ {{{
+ public class LeakingServlet extends HttpServlet {
+       private GenericObjectPool objectPool;
  
- TODO : example with the Evictor thread of dbcp
+       protected void doGet(HttpServletRequest request,
+                       HttpServletResponse response) throws ServletException, 
IOException {
+               response.getWriter().println("Number of idle objects in the 
pool :"+objectPool.getNumIdle());
+       }
+ 
+       @Override
+       public void init() throws ServletException {
+               objectPool = new GenericObjectPool();
+               objectPool.setFactory(new BasePoolableObjectFactory() {
+                       private AtomicInteger counter = new AtomicInteger(0);
+ 
+                       @Override
+                       public Object makeObject() throws Exception {
+                               String str = "Object #" + 
counter.incrementAndGet();
+                               System.out.println("Creating "+str);
+                               return str;
+                       }
+ 
+                       @Override
+                       public void destroyObject(Object obj) throws Exception {
+                               System.out.println("Destroying "+obj);
+                       }
+               });
+               objectPool.setMinIdle(3);
+               objectPool.setTimeBetweenEvictionRunsMillis(1000);
+       }
+ 
+       @Override
+       public void destroy() {
+               try {
+                       objectPool.close();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+ }
+ }}}
+ 
+ The call to {{{GenericObjectPool.setTimeBetweenEvictionRunsMillis)}}} 
actually starts or reuses a {{{java.lang.Timer}}} shared between all 
{{{GenericObjectPool}}} instances. As long as a pool is running and at least 
one pool is using the timer eviction feature, the Timer lives.
+ 
+ If there's no other webapp using commons-pool, there's no leak : when we stop 
the webapp, the servlet is stopped and the pool is closed. If it was the only 
pool in use, the Timer thread is also stopped and there's no leak.
+ 
+ Now, imagine that there are 2 webapps using commons-pool with the timer 
eviction feature (imagine the above servlet is deployed in 2 webapps A and B).
+ Suppose webapp A is deployed, then B. Since the commons-pool jar is shared 
between both webapps, only one Timer thread is spawned, with 2 {{{TimerTask}}}, 
one for each webapp, to handle the eviction of each pool instance.
+ 
+ Then, if we stop webapp A, boom it's leaking! the Timer thread has its 
context classloader set to the {{{WebAppClassLoader}}} of webapp A. This is 
somehow a [[http://issues.apache.org/jira/browse/POOL-161|bug of 
commons-pool]], but tomcat 6.0.24 tries to help :
+ 
+ {{{
+ INFO: HTMLManager: stop: Stopping web application at '/testWeb'
+ Destroying Object #3
+ Destroying Object #2
+ Destroying Object #1
+ Mar 21, 2010 9:26:36 PM org.apache.catalina.loader.WebappClassLoader 
clearReferencesStopTimerThread
+ SEVERE: A web application appears to have started a TimerThread named 
[Timer-0] via the java.util.Timer API but has failed to stop it. To prevent a 
memory leak, the timer (and hence the associated thread) has been forcibly 
cancelled. 
+ }}}
+ 
+ So the leak is fixed, but unfortunately there's a side effect : it broke 
webapp B eviction timer.
+ 
+ (TODO: file a bug report to make the clearReferencesStopTimerThread optional 
and disabled by default)
+ 
+ Note: as of 6.0.24, by default tomcat stops threads of class 
{{{java.util.TimerThread}}} whose context classloader is the 
{{{WebAppClassLoader}}} of the app being stopped. It does not stop other 
threads, it only warns about them. It can try to stop them if the 
{{{clearReferencesStopThreads}}} option of the standard context is set to true.
  
  === Threads spawned by JRE classes ===
  
+ Just like third-party libraries may spawn threads that provoke leaks, some 
JRE classes also spawn threads that inherit from the current class loader and 
thus provoke leaks.
+ 
+ Instead of trying to stop such threads, tomcat prefers to force the creation 
of such threads when the container is started, before webapps are started. The 
{{{JreMemoryLeakPreventionListener}}} does it for a few known offenders in the 
JRE.
+ 
  == Child classloaders ==
  
+ When an app is stopped, Tomcat 6.0.24 detects leaks caused by 
{{{ThreadLocal}}}s and Threads context classloader only by checking for the 
current {{{WebAppClassLoader}}}. If a child classloader is involved, the leak 
is not detected. That should be 
[[https://issues.apache.org/bugzilla/show_bug.cgi?id=48837|improved in a future 
release]].
+ 
  == static class variables ==
+ 
+ When an app is stopped, Tomcat (even before 6.0.24) nullifies the value of 
all static class variables of classes loaded by the {{{WebAppClassLoader}}}. In 
some cases, it may fix a classloader leak (for example because of a custom 
{{{ThreadLocal}}} class, see above), but even if we still have a leak, it may 
decrease the amount of memory lost:
+ 
+ Imagine a class with the following variable :
+ {{{
+ private final static byte[] BUFFER = new byte[1024*1024]; //1MB buffer
+ }}}
+ 
+ Normally, the 1MB buffer should be freed when the app is stopped, but only if 
the classloader itself can be garbage-collected.
+ Since there are still possibilities to have a leak of the classloader, 
clearing the BUFFER variable allows to recover 1MB of memory.
  
  == LogFactory ==
  

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to