Danilo, I implemented the wrapper you described here: http://mail-archives.apache.org/mod_mbox/db-ojb-user/200506.mbox/[EMAIL PROTECTED]
This didn't clean up any of the objects I have left over after my application shuts down. After the application is stopped in Tomcat, the wrapper class is pointed to by PersistenceBrokerFactoryFactory.singleton which never gets null'd out (and other static variables still hold references such as MetadataManager.singleton). I guess I'd like to see a shutdown() or destroy() method at some level that would clear out all of these static references. Bob -----Original Message----- From: Danilo Tommasina [mailto:[EMAIL PROTECTED] Sent: Friday, July 15, 2005 3:33 AM To: OJB Users List Subject: Re: Cleaning up OJB when shutting down an application Hi Armin, Below you can find a possible patch for the PersistenceBrokerThreadMapping, this also contains a shutdown() method to guarantee that the PersistenceBrokerThreadMapping is cleaned up correctly even if PersistenceBrokers are not closed correctly. I would also suggest adding a central shutdown() method (where?) that should call: - PersistenceBrokerFactory.releaseAllInstances() - ConnectionFactoryFactory.getInstance().createConnectionFactory().releaseAllResources() - The new call to PersistenceBrokerThreadMapping.shutdown() We are also executing following calls, these don't seem to be necessary if the 'evil ThreadLocal memory leak' is solved, include them at your choice. We were using these to reduce the amount of leaked memory before applying the workaround. Note that some more checks may be necessary if the shutdown is called on an uninitialised OJB instance (errors in the config, connection failure, ...) PersistenceBroker pb = null; try { pb = PersistenceBrokerFactory.defaultPersistenceBroker(); pb.clearCache(); // Clear complete OJB cache } catch ( PersistenceBrokerException pbe ) { // Silently ignore, this error should be handled somewhere else (initialsiation of OJB failed } finally { if ( pb != null ) { pb.close(); } } And finally MetadataManager.getInstance().removeAllProfiles() ---------------------- patched PersistenceBrokerThreadMapping, I also allowed myself to add some missing Javadoc ;) ---------------------- public class PersistenceBrokerThreadMapping { /** A Collection of all HashMaps added to the <CODE>ThreadLocal currentBrokerMap</CODE> that are still -alive-. * If all the PersistenceBrokers are always correctly closed, the Collection should remain empty. * The Collection is iterated trough when calling the <CODE>shutdown()</CODE> method and all the maps that are * still alive will be cleared. */ private static Collection loadedHMs = new HashSet(); // NEW /** * The hashmap that maps PBKeys to current brokers for the thread */ private static ThreadLocal currentBrokerMap = new ThreadLocal(); /** Mark a PersistenceBroker as preferred choice for current Thread * @param key The PBKey the broker is associated to * @param broker The PersistenceBroker to mark as current */ public static void setCurrentPersistenceBroker(PBKey key, PersistenceBroker broker) throws PBFactoryException { HashMap map = (HashMap) currentBrokerMap.get(); WeakHashMap set = null; if (map == null) { map = new HashMap(); currentBrokerMap.set(map); loadedHMs.add( map ); // NEW } else { set = (WeakHashMap) map.get(key); } if (set == null) { // We emulate weak HashSet using WeakHashMap set = new WeakHashMap(); map.put(key, set); } set.put(broker, null); } /** Unmark a PersistenceBroker as preferred choice for current Thread * @param key The PBKey the broker is associated to * @param broker The PersistenceBroker to unmark */ public static void unsetCurrentPersistenceBroker(PBKey key, PersistenceBroker broker) throws PBFactoryException { HashMap map = (HashMap) currentBrokerMap.get(); WeakHashMap set = null; if (map != null) { set = (WeakHashMap) map.get(key); if (set != null) { set.remove(broker); if ( set.isEmpty() ) { // NEW map.remove( key ); // NEW } // NEW } if ( map.isEmpty() ) { // NEW currentBrokerMap.set( null ); // NEW loadedHMs.remove( map ); // NEW } // NEW } } /** * Return the current open [EMAIL PROTECTED] org.apache.ojb.broker.PersistenceBroker} * instance for the given [EMAIL PROTECTED] org.apache.ojb.broker.PBKey}, if any. * @param key * @return null if no open [EMAIL PROTECTED] org.apache.ojb.broker.PersistenceBroker} found. */ public static PersistenceBroker currentPersistenceBroker(PBKey key) throws PBFactoryException, PersistenceBrokerException { HashMap map = (HashMap) currentBrokerMap.get(); WeakHashMap set; PersistenceBroker broker = null; if (map == null) { return null; } set = (WeakHashMap) map.get(key); if (set == null) { return null; } // seek for an open broker, preferably in transaction for (Iterator it = set.keySet().iterator(); it.hasNext(); ) { PersistenceBroker tmp = (PersistenceBroker) it.next(); if (tmp == null || tmp.isClosed()) { it.remove(); continue; } broker = tmp; if (tmp.isInTransaction()) { break; // the best choice found } } return broker; } /** Clean up static fields and any registered ThreadLocal contents to grant a clean * shutdown/reload of OJB within hot-deployable applications. */ public static void shutdown() { for ( Iterator it = loadedHMs.iterator(); it.hasNext(); ) { ((HashMap) it.next()).clear(); } loadedHMs.clear(); loadedHMs = null; currentBrokerMap = null; } } > Hi Danilo, Bob, > > AFAIK there was no patch checked in conjunction with PBThreadMapping. > As you said the threads in tomcat will be recycled and it seems that > ThreadLocal will cause a memory leak in this case: > http://www.jroller.com/page/tackline/20050310 > (sounds similar, but maybe I'm wrong) > > So we need some kind of shutdown method in PBF and in PBThreadMapping. > Could you both summarize the needed changes I will check in a patch. I > found the patch for PBThreadMapping (the new "shutdown"-method). > What's needed too? > > regards, > Armin > > Danilo Tommasina wrote: > >> Hello, >> >> please see my post 'ThreadLocal causing memory leak' of 9. Jun. 2005, >> this is the same problem described there. I posted some code that can >> be used as temporary solution or workaround and discussed a bit about >> the issue with Martin Kalén, however I do not know the current >> status... >> >> Both the workaround in the PersistenceBrokerFactoryDefaultImpl and my >> proposed 'clean' solution in the PersistenceBrokerThreadMapping (I >> sent the definitive code directly to Martin) seems to work correctly >> in our application. To note is that we are using only the PB API and >> are not using proxies. The workaround in the >> PersistenceBrokerFactoryDefaultImpl 'may' cause problems or >> performance issues with proxies, however I cannot test it, I did just >> a short and not very deep analysis of the code searching for possible >> side effects. >> >> As I cannot currently access the apache CVS (it seems to be flooded >> and it is currently down), I cannot say if the issue has already been >> patched in the latest CVS version or not. >> >> bye >> Danilo >> >> Glugla, Robert T wrote: >> >>> Environment: >>> >>> OJB: 1.0.3 >>> JProfiler: 4.0.1 >>> Tomcat: 5.0.19 >>> JVM: Sun 1.4.2_06-b03 >>> >>> While profiling our OJB application, we noticed that after we shut >>> it down in Tomcat, we had plenty of org.apache.ojb.broker.* and >>> org.apache.ojb.metadata.* objects left behind in memory. Using >>> JProfiler we tracked it down to several static variables not getting >>> cleared out >>> including: >>> >>> PersistenceBrokerFactoryFactory.singleton >>> MetadataManager.singleton >>> ...several others... >>> >>> Does anyone have any suggestions as to how to clean these up >>> properly? I looked for destroy methods and couldn't find any. As a >>> test, I downloaded the OJB source and added destroy methods to >>> PersistenceBrokerFactoryFactory & MetadataManager that I called from >>> a context listener and it worked ok. Really, really don't want to >>> do this myself. I'm guessing I'm just overlooking some easy way for >>> cleaning these up already provided in OJB. >>> >>> Any suggestions? >>> >>> Thanks. >>> >>> Bob Glugla >>> Boeing >>> >>> -------------------------------------------------------------------- >>> - >>> To unsubscribe, e-mail: [EMAIL PROTECTED] >>> For additional commands, e-mail: [EMAIL PROTECTED] >>> >> >> [EMAIL PROTECTED] >> www.risksys.com >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [EMAIL PROTECTED] >> For additional commands, e-mail: [EMAIL PROTECTED] >> >> >> > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > -- Danilo Tommasina, Dipl. Ing. FH Telecom Software Engineer, Chief Software Architect RCS Riskmanagement Concepts Systems AG Technoparkstrasse 1 CH-8005 Zuerich T: +41 1 445 29 08 [EMAIL PROTECTED] www.risksys.com --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]