From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2006-03-08 10:39:08
|
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 |