Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48837
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 24 Nov 2010 21:28:33 +0000 (21:28 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 24 Nov 2010 21:28:33 +0000 (21:28 +0000)
Extend thread local memory leak detection to include classes loaded by subordinate class loaders to the web application's class loader such as the Jasper class loader.
Based on a patch by Sylvain Laurent.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1038831 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/loader/WebappClassLoader.java
webapps/docs/changelog.xml

index 36b7d52..13f0714 100644 (file)
@@ -2183,7 +2183,7 @@ public class WebappClassLoader
         for (Thread thread : threads) {
             if (thread != null) {
                 ClassLoader ccl = thread.getContextClassLoader();
-                if (ccl != null && ccl == this) {
+                if (ccl == this) {
                     // Don't warn about this thread
                     if (thread == Thread.currentThread()) {
                         continue;
@@ -2424,8 +2424,8 @@ public class WebappClassLoader
                         boolean remove = false;
                         // Check the key
                         Object key = ((Reference<?>) table[j]).get();
-                        if (this.equals(key) || (key != null &&
-                                this == key.getClass().getClassLoader())) {
+                        if (this.equals(key) ||
+                                isLoadedByThisWebAppClassLoader(key)) {
                             remove = true;
                         }
                         // Check the value
@@ -2433,15 +2433,15 @@ public class WebappClassLoader
                             table[j].getClass().getDeclaredField("value");
                         valueField.setAccessible(true);
                         Object value = valueField.get(table[j]);
-                        if (this.equals(value) || (value != null &&
-                                this == value.getClass().getClassLoader())) {
+                        if (this.equals(value) ||
+                                isLoadedByThisWebAppClassLoader(value)) {
                             remove = true;
                         }
                         if (remove) {
                             Object[] args = new Object[5];
                             args[0] = contextName;
                             if (key != null) {
-                                args[1] = key.getClass().getCanonicalName();
+                                args[1] = getPrettyClassName(key.getClass());
                                 try {
                                     args[2] = key.toString();
                                 } catch (Exception e) {
@@ -2453,7 +2453,7 @@ public class WebappClassLoader
                                 }
                             }
                             if (value != null) {
-                                args[3] = value.getClass().getCanonicalName();
+                                args[3] = getPrettyClassName(value.getClass());
                                 try {
                                     args[4] = value.toString();
                                 } catch (Exception e) {
@@ -2503,6 +2503,33 @@ public class WebappClassLoader
         }
     }
 
+    private String getPrettyClassName(Class<?> clazz) {
+        String name = clazz.getCanonicalName();
+        if (name==null){
+            name = clazz.getName();
+        }
+        return name;
+    }
+    
+    /**
+     * @param o object to test
+     * @return <code>true</code> if o has been loaded by the current classloader
+     * or one of its descendants.
+     */
+    private boolean isLoadedByThisWebAppClassLoader(Object o) {
+        if (o == null) {
+            return false;
+        }
+        ClassLoader cl = o.getClass().getClassLoader();
+        while (cl != null) {
+            if(cl == this) {
+                return true;
+            }
+            cl = cl.getParent();
+        }
+        return false;
+    }
+        
     /*
      * Get the set of current threads as an array.
      */
index ab8467d..23de11a 100644 (file)
 <section name="Tomcat 7.0.6 (markt)">
   <subsection name="Catalina">
     <changelog>
+      <add>
+        <bug>48837</bug>: Extend thread local memory leak detection to include
+        classes loaded by subordinate class loaders to the web
+        application&apos;s class loader such as the Jasper class loader. Based
+        on a patch by Sylvain Laurent. (markt)
+      </add>
       <fix>
         <bug>49650</bug>: Remove unnecessary entries package.access property
         defined in catalina.properties. Patch provided by Owen Farrell. (markt)