From dcf1ef77d77ba665ea0979fcefa9695ec0a4d6a4 Mon Sep 17 00:00:00 2001 From: slaurent Date: Fri, 7 Jan 2011 22:56:30 +0000 Subject: [PATCH] bug 50556: improve JreMemoryLeakPreventionListener against leak caused by LdapPoolManager https://issues.apache.org/bugzilla/show_bug.cgi?id=50556 git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1056553 13f79535-47bb-0310-9956-ffa450edef68 --- .../core/JreMemoryLeakPreventionListener.java | 32 ++++++++++++++++++++++ .../apache/catalina/core/LocalStrings.properties | 1 + webapps/docs/changelog.xml | 7 +++++ webapps/docs/config/listeners.xml | 13 +++++++++ 4 files changed, 53 insertions(+) diff --git a/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java b/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java index 2e3a3772a..1b2b3699d 100644 --- a/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java +++ b/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java @@ -35,6 +35,8 @@ import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; +import com.sun.jndi.ldap.LdapPoolManager; + /** * Provide a workaround for known places where the Java Runtime environment can * cause a memory leak or lock files. @@ -162,6 +164,20 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener { this.xmlParsingProtection = xmlParsingProtection; } + /** + * {@link LdapPoolManager} spawns a thread when it is initialized if the + * system property com.sun.jndi.ldap.connect.pool.timeout is + * greater than 0. + * That thread inherits the context class loader of the current thread, so + * that there my be a web application class loader leak if the web app + * is the first to use {@link LdapPoolManager}. + */ + private boolean ldapPoolProtection = true; + public boolean isLdapPoolProtection() { return ldapPoolProtection; } + public void setLdapPoolProtection(boolean ldapPoolProtection) { + this.ldapPoolProtection = ldapPoolProtection; + } + @Override public void lifecycleEvent(LifecycleEvent event) { // Initialise these classes when Tomcat starts @@ -358,6 +374,22 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener { e); } } + + if (ldapPoolProtection) { + try { + Class.forName("com.sun.jndi.ldap.LdapPoolManager"); + } catch (ClassNotFoundException e) { + if (System.getProperty("java.vendor").startsWith( + "Sun")) { + log.error(sm.getString( + "jreLeakListener.ldapPoolManagerFail"), e); + } else { + log.debug(sm.getString( + "jreLeakListener.ldapPoolManagerFail"), e); + } + } + } + } finally { Thread.currentThread().setContextClassLoader(loader); } diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties index e3f001820..ef4f866c1 100644 --- a/java/org/apache/catalina/core/LocalStrings.properties +++ b/java/org/apache/catalina/core/LocalStrings.properties @@ -82,6 +82,7 @@ jreLeakListener.gcDaemonFail=Failed to trigger creation of the GC Daemon thread jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching by default jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class +jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. naming.wsdlFailed=Failed to find wsdl file: {0} naming.bindFailed=Failed to bind object: {0} naming.jmxRegistrationFailed=Failed to register in JMX: {0} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index e3cf8d02f..53c87ab74 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -200,6 +200,13 @@ 50554: Code clean up. (markt) + + 50556: Improve JreMemoryLeakPreventionListener to prevent + a potential class loader leak caused by a thread spawned when the class + com.sun.jndi.ldap.LdapPoolManager is initialized and the + system property com.sun.jndi.ldap.connect.pool.timeout is + set to a value greater than 0. (slaurent) + diff --git a/webapps/docs/config/listeners.xml b/webapps/docs/config/listeners.xml index 009786a45..195e3fbf4 100644 --- a/webapps/docs/config/listeners.xml +++ b/webapps/docs/config/listeners.xml @@ -270,6 +270,19 @@ service:jmx:rmi://<hostname>:10002/jndi/rmi://<hostname>:10001/jmxrm trigger a memory leak on reload. Defaults to true.

+ +

Enables protection so that the PoolCleaner thread started by + com.sun.jndi.ldap.LdapPoolManager does not result in a + memory leak. The thread is started the first time the + LdapPoolManager class is used if the system property + com.sun.jndi.ldap.connect.pool.timeout is set to a value + greater than 0. Without this protection, if a web application uses this + class the PoolCleaner thread will be configured with the thread's + context class loader set to the web application class loader which in + turn will trigger a memory leak on reload. Defaults to + true.

+
+

Enables protection so that usage of the javax.security.auth.login.Configuration class by a web -- 2.11.0