From: Keats K. <ke...@xa...> - 2006-03-08 15:54:21
|
I haven't had a chance to validate what you are saying, but I know there has been a longstanding issue with getting WM Web apps to unload properly. It sounds like you've finally nailed it. I think your approach of adding a destroy method to the Broker makes sense. If you're willing to work on it that would be great. Nice work. Keats Alex Twisleton-Wykeham-Fiennes wrote: >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 > > > |