Thread leak with ReloadingCacheManager

Alex Twisleton-Wykeham-Fiennes <[email protected]> Wed, 8 Mar 2006 10:39:23 +0000
Newsgroups gmane.comp.java.webmacro.user
Message-ID <[email protected]>
All,

I've just been spending a couple of days trying to track down why memory gets 
consumed when reloading the same web application under tomcat which according 
to my research is related to class loader confusion [1].

During the course of my testing (running OptimizeIt across the tomcat5 process 
and analysing class loading and object creation across multiple reloads), 
I've been noticing the number of Threads growing with each reload which 
didn't seem correct at all.

The increasing threads were getting allocated by ReloadingCacheManager and 
where being utilised by the ClockDaemon process for triggering the expiration 
of assets from the template and url Providers (using the standard webmacro 
defaults file).

These would normally get destroyed when the destroy() method was invoked on 
the ReloadingCacheManager, but I couldn't find any where that enabled me to 
do this easily.  I would have expected this to be invoked in the destroy() 
method of WMServlet but this is not the case:-
    public synchronized void destroy ()
    {
        stop();
        _log.notice("stopped: " + this);
        _wm = null;
        _started = false;
        super.destroy();
    }

In the end, I found it very hard to find a way to cleanly persuade the 
webmacro instance to shut itself down properly, and ended up putting 
something like this in my stop() method for my subclass of WMServlet:-

  protected void stop() 
  {
    // tidy up my stuff... <snip>
    Broker broker = getBroker();
    try {
      Provider templateProvider = broker.getProvider("template");
      templateProvider.destroy();
      Provider urlProvider = broker.getProvider("url");
      urlProvider.destroy();
    } catch (NotFoundException nfEx) {
      nfEx.printStackTrace();
    }
    super.stop();
  }

Now this nicely tidies up the appropriate resources and when I reload this 
application lots of times the thread count stays consistent, my memory is 
much more under control and everything is a bit smoother.

So, my question is:-

Assuming that ReloadingCacheManager has to be destroy()ed correctly to get it 
to shut down, and assuming that the application author doesn't know which 
Providers are going to be implemented using a ReloadingCacheManager (as it is 
defined by the properties classes at runtime), then what would be the 
"correct" way of ensuring that the framework is correctly shut down?

Previously there was a definition of WebMacro.destroy() that stated "Call this 
method when you are finished with WebMacro. If you don't call this method, 
the Broker and all of WebMacro's caches may not be properly shut down, 
potentially resulting in loss of data, and wasted memory. This method is 
called in the finalizer, but it is best to call it as soon as you know you 
are done with WebMacro.", but this has since been dropped from the package.

My gut feeling is that there should be a destroy() method on the Broker that 
then invokes destroy() on all of the sub-components that it is maintaining 
references to, but I am not that familiar with the webmacro hierarchy...

All tests have been run against 2.0b1, but the changelog to 2.0RC1 doesn't 
touch upon any of these changes as far as I can see.

Alex

[1] 
http://opensource2.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669


-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642