Author: markt
Date: Fri Jan 28 13:03:57 2011
New Revision: 1064652

URL: http://svn.apache.org/viewvc?rev=1064652&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50642
Better fix for HttpClient keep-alive thread triggered memory leaks

Modified:
    
tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
    tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
    tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties
    tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoader.java
    tomcat/trunk/java/org/apache/catalina/loader/WebappLoader.java
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/context.xml
    tomcat/trunk/webapps/docs/config/listeners.xml

Modified: 
tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java 
(original)
+++ 
tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java 
Fri Jan 28 13:03:57 2011
@@ -82,19 +82,6 @@ public class JreMemoryLeakPreventionList
 
      /**
       * Protect against the memory leak caused when the first call to
-      * <code>sun.net.www.http.HttpClient</code> is triggered by a web
-      * application. This first call will start a KeepAlive thread with the
-      * thread's context class loader configured to be the web application 
class
-      * loader. Defaults to <code>true</code>.
-      */
-     private boolean keepAliveProtection = true;
-     public boolean isKeepAliveProtection() { return keepAliveProtection; }
-     public void setKeepAliveProtection(boolean keepAliveProtection) {
-         this.keepAliveProtection = keepAliveProtection;
-     }
-    
-     /**
-      * Protect against the memory leak caused when the first call to
       * <code>javax.security.auth.Policy</code> is triggered by a web
       * application. This first call populate a static variable with a 
reference
       * to the context class loader. Defaults to <code>true</code>.
@@ -252,27 +239,6 @@ public class JreMemoryLeakPreventionList
                 }
     
                 /*
-                 * When a servlet opens a connection using a URL it will use
-                 * sun.net.www.http.HttpClient which keeps a static reference 
to
-                 * a keep-alive cache which is loaded using the web application
-                 * class loader.
-                 */
-                if (keepAliveProtection) {
-                    try {
-                        Class.forName("sun.net.www.http.HttpClient");
-                    } catch (ClassNotFoundException e) {
-                        if (System.getProperty("java.vendor").startsWith(
-                                "Sun")) {
-                            log.error(sm.getString(
-                                    "jreLeakListener.keepAliveFail"), e);
-                        } else {
-                            log.debug(sm.getString(
-                                    "jreLeakListener.keepAliveFail"), e);
-                        }
-                    }
-                }
-                
-                /*
                  * Calling getPolicy retains a static reference to the context 
                  * class loader.
                  */

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Fri Jan 28 
13:03:57 2011
@@ -801,6 +801,16 @@ public class StandardContext extends Con
     private boolean clearReferencesStopTimerThreads = false;
 
     /**
+     * If an HttpClient keep-alive timer thread has been started by this web
+     * application and is still running, should Tomcat change the context class
+     * loader from the current {@link WebappClassLoader} to
+     * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the
+     * keep-alive timer thread will stop on its own once the keep-alives all
+     * expire however, on a busy system that might not happen for some time.
+     */
+    private boolean clearReferencesHttpClientKeepAliveThread = true;
+
+    /**
      * Should Tomcat renew the threads of the thread pool when the application
      * is stopped to avoid memory leaks because of uncleaned ThreadLocal
      * variables. This also requires that the threadRenewalDelay property of 
the
@@ -2535,6 +2545,28 @@ public class StandardContext extends Con
     }
 
 
+    /**
+     * Return the clearReferencesHttpClientKeepAliveThread flag for this
+     * Context.
+     */
+    public boolean getClearReferencesHttpClientKeepAliveThread() {
+        return (this.clearReferencesHttpClientKeepAliveThread);
+    }
+
+
+    /**
+     * Set the clearReferencesHttpClientKeepAliveThread feature for this
+     * Context.
+     *
+     * @param clearReferencesHttpClientKeepAliveThread The new flag value
+     */
+    public void setClearReferencesHttpClientKeepAliveThread(
+            boolean clearReferencesHttpClientKeepAliveThread) {
+        this.clearReferencesHttpClientKeepAliveThread =
+            clearReferencesHttpClientKeepAliveThread;
+    }
+
+
     public boolean getRenewThreadsWhenStoppingContext() {
         return this.renewThreadsWhenStoppingContext;
     }

Modified: tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties Fri 
Jan 28 13:03:57 2011
@@ -50,6 +50,7 @@ webappClassLoader.checkThreadLocalsForLe
 webappClassLoader.checkThreadLocalsForLeaks=The web application [{0}] created 
a ThreadLocal with key of type [{1}] (value [{2}]) and a value of type [{3}] 
(value [{4}]) but failed to remove it when the web application was stopped. 
Threads are going to be renewed over time to try and avoid a probable memory 
leak. 
 webappClassLoader.checkThreadLocalsForLeaksDebug=The web application [{0}] 
created a ThreadLocal with key of type [{1}] (value [{2}]). The ThreadLocal has 
been correctly set to null and the key will be removed by GC.
 webappClassLoader.checkThreadLocalsForLeaksFail=Failed to check for 
ThreadLocal references for web application [{0}]
+webappClassLoader.checkThreadsHttpClient=Found HttpClient keep-alive thread 
using web application class loader. Fixed by switching thread to the parent 
class loader.
 webappClassLoader.stopThreadFail=Failed to terminate thread named [{0}] for 
web application [{1}]
 webappClassLoader.stopTimerThreadFail=Failed to terminate TimerThread named 
[{0}] for web application [{1}]
 webappClassLoader.validationErrorJarPath=Unable to validate JAR entry with 
name {0}

Modified: tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoader.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoader.java?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoader.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoader.java Fri Jan 
28 13:03:57 2011
@@ -132,8 +132,10 @@ public class WebappClassLoader
     private static final List<String> JVM_THREAD_GROUP_NAMES =
         new ArrayList<String>();
 
+    private static final String JVN_THREAD_GROUP_SYSTEM = "system";
+    
     static {
-        JVM_THREAD_GROUP_NAMES.add("system");
+        JVM_THREAD_GROUP_NAMES.add(JVN_THREAD_GROUP_SYSTEM);
         JVM_THREAD_GROUP_NAMES.add("RMI Runtime");
     }
 
@@ -465,6 +467,15 @@ public class WebappClassLoader
      */
     private boolean clearReferencesLogFactoryRelease = true;
 
+    /**
+     * If an HttpClient keep-alive timer thread has been started by this web
+     * application and is still running, should Tomcat change the context class
+     * loader from the current {@link WebappClassLoader} to
+     * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the
+     * keep-alive timer thread will stop on its own once the keep-alives all
+     * expire however, on a busy system that might not happen for some time.
+     */
+    private boolean clearReferencesHttpClientKeepAliveThread = true;
     
     /**
      * Name of associated context used with logging and JMX to associate with
@@ -745,6 +756,28 @@ public class WebappClassLoader
      }
 
 
+     /**
+      * Return the clearReferencesHttpClientKeepAliveThread flag for this
+      * Context.
+      */
+     public boolean getClearReferencesHttpClientKeepAliveThread() {
+         return (this.clearReferencesHttpClientKeepAliveThread);
+     }
+
+
+     /**
+      * Set the clearReferencesHttpClientKeepAliveThread feature for this
+      * Context.
+      *
+      * @param clearReferencesHttpClientKeepAliveThread The new flag value
+      */
+     public void setClearReferencesHttpClientKeepAliveThread(
+             boolean clearReferencesHttpClientKeepAliveThread) {
+         this.clearReferencesHttpClientKeepAliveThread =
+             clearReferencesHttpClientKeepAliveThread;
+     }
+
+     
     // ------------------------------------------------------- Reloader Methods
 
 
@@ -2166,10 +2199,20 @@ public class WebappClassLoader
                         continue;
                     }
 
-                    // Don't warn about JVM controlled threads
+                    // JVM controlled threads
                     ThreadGroup tg = thread.getThreadGroup();
                     if (tg != null &&
                             JVM_THREAD_GROUP_NAMES.contains(tg.getName())) {
+
+                        // HttpClient keep-alive threads
+                        if (clearReferencesHttpClientKeepAliveThread &&
+                                thread.getName().equals("Keep-Alive-Timer")) {
+                            thread.setContextClassLoader(parent);
+                            log.debug(sm.getString(
+                                    
"webappClassLoader.checkThreadsHttpClient"));
+                        }
+                    
+                        // Don't warn about remaining JVM controlled threads
                         continue;
                     }
                    

Modified: tomcat/trunk/java/org/apache/catalina/loader/WebappLoader.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/WebappLoader.java?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/loader/WebappLoader.java (original)
+++ tomcat/trunk/java/org/apache/catalina/loader/WebappLoader.java Fri Jan 28 
13:03:57 2011
@@ -591,6 +591,8 @@ public class WebappLoader extends Lifecy
                         ((StandardContext) 
container).getClearReferencesStopThreads());
                 classLoader.setClearReferencesStopTimerThreads(
                         ((StandardContext) 
container).getClearReferencesStopTimerThreads());
+                classLoader.setClearReferencesHttpClientKeepAliveThread(
+                        ((StandardContext) 
container).getClearReferencesHttpClientKeepAliveThread());
             }
 
             for (int i = 0; i < repositories.length; i++) {

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Jan 28 13:03:57 2011
@@ -98,6 +98,12 @@
         Use getName() instead of logName() in error messages in 
StandardContext.
         (kkolinko)
       </update>
+      <fix>
+        <bug>50642</bug>: Move the HttpClient keep-alive thread memory leak
+        protection from the JreMemoryLeakPreventionListener to the
+        WebappClassLoader since the thread that triggers the memory leak is
+        created on demand. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">

Modified: tomcat/trunk/webapps/docs/config/context.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/context.xml?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/context.xml (original)
+++ tomcat/trunk/webapps/docs/config/context.xml Fri Jan 28 13:03:57 2011
@@ -503,6 +503,18 @@
         of the flag is <code>true</code>.</p>
       </attribute>
 
+      <attribute name="clearReferencesHttpClientKeepAliveThread" required = 
"false">
+        <p>If <code>true</code> and an HttpClient keep-alive timer thread has
+        been started by this web application and is still running, Tomcat will
+        change the context class loader for that thread from the current
+        <code>WebappClassLoader</code> to
+        <code>WebappClassLoader#parent</code> to prevent a memory leak. Note
+        that the keep-alive timer thread will stop on its own once the
+        keep-alives all expire however, on a busy system that might not happen
+        for some time. If not specified, the default value of
+        <code>true</code> will be used.</p>
+      </attribute>
+
       <attribute name="clearReferencesStatic" required = "false">
         <p>If <code>true</code>, Tomcat attempts to null out any static or 
final
         fields from loaded classes when a web application is stopped as a work

Modified: tomcat/trunk/webapps/docs/config/listeners.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/listeners.xml?rev=1064652&r1=1064651&r2=1064652&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/listeners.xml (original)
+++ tomcat/trunk/webapps/docs/config/listeners.xml Fri Jan 28 13:03:57 2011
@@ -260,16 +260,6 @@ service:jmx:rmi://&lt;hostname&gt;:10002
         startup on non-Sun JVMs. The default is <code>true</code>.</p>
       </attribute>
 
-      <attribute name="keepAliveProtection" required="false">
-        <p>Enables protection so that the KeepAlive thread started by
-        <code>sun.net.www.http.HttpClient</code> does not result in a memory
-        leak. The thread is started the first time the <code>HttpClient</code>
-        class is used. Without this protection, if a web application uses this
-        class the KeepAlive 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 <code>true</code>.</p>
-      </attribute>
-
       <attribute name="ldapPoolProtection" required="false">
         <p>Enables protection so that the PoolCleaner thread started by
         <code>com.sun.jndi.ldap.LdapPoolManager</code> does not result in a 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to