Re: More sources of Tomcat memory leaks
) object); } return false; } /** * Clear a collection recursively. * @param info for logging purposes. * @param iterable the Collection to be cleared. * @return false. */ private boolean clearIterableRecursive(String info, Iterable iterable) { Vector goners = new Vector(); Iterator iterator = iterable.iterator(); // Special treatment for Collections // in case the Iterator cannot remove // but the Collection itself can. if (iterable instanceof Collection) { Collection collection = (Collection) iterable; for (Object key: collection) { if (clearRecursive(info, key)) { goners.add(key); } } for (Object goner: goners.toArray()) { System.out.println(info + : removed key referring ClassLoader from Collection); collection.remove(goner); } return false; } while (iterator.hasNext()) { if (clearRecursive(info, iterator.next())) { iterator.remove(); } } return false; } /** * Clear a map recursively. * @param info for logging purposes. * @param map the Map to be cleared. * @return false. */ private boolean clearMapRecursive(final String info, final MapObject, Object map) { Vector goners = new Vector(); Object value; for (Object key: map.keySet()) { if (clearRecursive(info, key)) { goners.add(key); } else { value = map.get(key); if (clearRecursive(info, value)) { try { map.put(key, null); System.out.println(info + : removed value referring ClassLoader from Map); } catch (NullPointerException n) { goners.add(key); } } } } for (Object goner: goners.toArray()) { System.out.println(info + : removed key referring ClassLoader from Map); map.remove(goner); } return false; } Hope you 'll enjoy Arjen -- View this message in context: http://old.nabble.com/More-sources-of-Tomcat-memory-leaks-tp29264214p29297364.html Sent from the Tomcat - Dev mailing list archive at Nabble.com. - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
Re: More sources of Tomcat memory leaks
On 29.07.2010 17:00, Arjen Knibbe wrote: I searched for an upgrading to Tomcat 7 manual in the Tomcat documentation to check if the new JreMemoryLeakPreventionListener is mentioned, but I could not find any guidelines for upgrading... There is some info about major version differences at http://tomcat.apache.org/migration.html which is not below the TC 7 docs, so it's common people don't find it :) Regards, Rainer - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
Re: More sources of Tomcat memory leaks
containsKey can throw ClassCastException // So, use the surest way for (Object item: seen) { if (item == seen) { return false; } } seen.add(object); if (object instanceof Map) { return clearMapRecursive(info, (MapObject, Object) object); } else if (object instanceof Iterable) { return clearIterableRecursive(info, (Iterable) object); } return false; } /** * Clear a collection recursively. * @param info for logging purposes. * @param iterable the Collection to be cleared. * @return false. */ private boolean clearIterableRecursive(String info, Iterable iterable) { Vector goners = new Vector(); Iterator iterator = iterable.iterator(); // Special treatment for Collections // in case the Iterator cannot remove // but the Collection itself can. if (iterable instanceof Collection) { Collection collection = (Collection) iterable; for (Object key: collection) { if (clearRecursive(info, key)) { goners.add(key); } } for (Object goner: goners.toArray()) { System.out.println(info + : removed key referring ClassLoader from Collection); collection.remove(goner); } return false; } while (iterator.hasNext()) { if (clearRecursive(info, iterator.next())) { iterator.remove(); } } return false; } /** * Clear a map recursively. * @param info for logging purposes. * @param map the Map to be cleared. * @return false. */ private boolean clearMapRecursive(final String info, final MapObject, Object map) { Vector goners = new Vector(); Object value; for (Object key: map.keySet()) { if (clearRecursive(info, key)) { goners.add(key); } else { value = map.get(key); if (clearRecursive(info, value)) { try { map.put(key, null); System.out.println(info + : removed value referring ClassLoader from Map); } catch (NullPointerException n) { goners.add(key); } } } } for (Object goner: goners.toArray()) { System.out.println(info + : removed key referring ClassLoader from Map); map.remove(goner); } return false; } Hope you 'll enjoy Arjen -- View this message in context: http://old.nabble.com/More-sources-of-Tomcat-memory-leaks-tp29264214p29297364.html Sent from the Tomcat - Dev mailing list archive at Nabble.com. - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
Re: More sources of Tomcat memory leaks
On 26/07/2010 09:16, Arjen Knibbe wrote: After being plaged by PermGen space OutOfMemoryErrors I came across an http://java.dzone.com/articles/memory-leak-protection-tomcat interview with Mark Thomas announcing the solution for these kinds of memory leaks. I upgraded Tomcat 6.0.26 on Solaris 5.8 machine and repeatedly deployed and undeployed my applications. However, the problem remained. After many weeks, I think I got it: Many, many thanks for your efforts and for writing this up. This looks great. Please could you create a Bugzilla entry (against Tomact 7) for each issue you identified so that this valuable work doesn't get forgotten about? 95% of the work should just be a copy and paste. Again, many thanks. Mark PS How do you fancy trying to fix some of these issues? Besides the enhanced WebappClassLoader the new Tomcat uses a Listener org.apache.catalina.core.JreMemoryLeakPreventionListener, that has to be included in the server.xml file. By upgrading, I missed that. The class javax.security.auth.Policy has a static member contextClassLoader that can refer to the WebappClassLoader. from jhat: h3Static reference from javax.security.auth.Policy.contextClassLoadersmall (from ../object/0xdc035580 class javax.security.auth.Policy) /small :/h3--gt; ../object/0xeb5a84a0 org.apache.catalina.loader.webappclassloa...@0xeb5a84a0 (157 bytes) br The class sun.rmi.server.LoaderHander has a static member LoaderTable that can contain the WebappClassLoader when using RMI. From jhat: h3Static reference from sun.rmi.server.LoaderHandler.loaderTablesmall (from ../object/0xdbf2b258 class sun.rmi.server.LoaderHandler) /small :/h3--gt; ../object/0xeb7b52d0 java.util.hash...@0xeb7b52d0 (40 bytes) (field table:)br --gt; ../object/0xeb7b52f8 [Ljava.util.HashMap$Entry;@0xeb7b52f8 (40 bytes) (Element 0 of [Ljava.util.HashMap$Entry;@0xeb7b52f8:)br --gt; ../object/0xeb7b5388 java.util.hashmap$en...@0xeb7b5388 (24 bytes) (field key:)br --gt; ../object/0xeb7b53a0 sun.rmi.server.loaderhandler$loader...@0xeb7b53a0 (20 bytes) (field parent:)br --gt; ../object/0xeb5a84a0 org.apache.catalina.loader.webappclassloa...@0xeb5a84a0 (157 bytes) br The clearReferencesThreadLocals() method of WebappClassLoader clears two Thread tables from references to the WebappClassLoader. When using axis, the tables can have a HashMap as key, which contains (possibly after many nested HashMaps) a class that was loaded by the WebappClassLoader. From jhat: h3Static reference from org.apache.catalina.ServerFactory.serversmall (from ../object/0xdba00178 class org.apache.catalina.ServerFactory) /small :/h3--gt; ../object/0xeb400668 org.apache.catalina.core.standardser...@0xeb400668 (67 bytes) (field services:)br --gt; ../object/0xeb4b4178 [Lorg.apache.catalina.Service;@0xeb4b4178 (12 bytes) (Element 0 of [Lorg.apache.catalina.Service;@0xeb4b4178:)br --gt; ../object/0xeb4b4188 org.apache.catalina.core.standardserv...@0xeb4b4188 (62 bytes) (field container:)br --gt; ../object/0xeb4b42c8 org.apache.catalina.core.standardeng...@0xeb4b42c8 (129 bytes) (field thread:)br --gt; ../object/0xeb58b6e0 java.lang.thr...@0xeb58b6e0 (104 bytes) (field threadLocals:)br --gt; ../object/0xeb58b800 java.lang.threadlocal$threadlocal...@0xeb58b800 (20 bytes) (field table:)br --gt; ../object/0xeb58b818 [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0xeb58b818 (72 bytes) (Element 8 of [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0xeb58b818:)br --gt; ../object/0xeb58b908 java.lang.threadlocal$threadlocalmap$en...@0xeb58b908 (28 bytes) (field value:)br --gt; ../object/0xeb58b928 java.util.hash...@0xeb58b928 (40 bytes) (field table:)br --gt; ../object/0xeb58b950 [Ljava.util.HashMap$Entry;@0xeb58b950 (72 bytes) (Element 0 of [Ljava.util.HashMap$Entry;@0xeb58b950:)br --gt; ../object/0xeb58bb40 java.util.hashmap$en...@0xeb58bb40 (24 bytes) (field key:)br --gt; ../object/0xdbe798a0 class org.apache.axis.types.Notation (84 bytes) (??:)br --gt; ../object/0xeb5a84a0 org.apache.catalina.loader.webappclassloa...@0xeb5a84a0 (157 bytes) br Suppose there is an web application A that uses a database and registers a Driver with the java.sql.DriverManager, and a web application B that doesn't use a database but has a jar file in its WEB-INF/lib directory that contains the same Driver. Suppose you unload webapplication B. Running the org.apache.catalina.loader.JdbcLeakPrevention class will actually register the Driver and leave it loaded! The cause is the way the DriverManager checks whether a ClassLoader has permission to load the Driver. It does that by calling ClassForName with the ClassLoader, which will load the class if the class has not been loaded by that ClassLoader. And loading a Driver triggers the Driver to register itself. Seems that the loop in org.apache.catalina.loader.JdbcLeakPrevention has to be run twice. I
More sources of Tomcat memory leaks
, clearing all deep references to the WebappClassLoader./li /ul After that, my classes were unloaded after undeploy. Arjen -- View this message in context: http://old.nabble.com/More-sources-of-Tomcat-memory-leaks-tp29264214p29264214.html Sent from the Tomcat - Dev mailing list archive at Nabble.com. - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org