Add rudimentary detection for PermGen memory leaks on web application reload. Only...
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 11 Feb 2010 20:32:09 +0000 (20:32 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 11 Feb 2010 20:32:09 +0000 (20:32 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@909134 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/core/StandardHost.java
java/org/apache/catalina/core/mbeans-descriptors.xml
java/org/apache/catalina/loader/WebappClassLoader.java

index a343e6e..8e11dec 100644 (file)
 package org.apache.catalina.core;
 
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
 
@@ -27,6 +32,7 @@ import org.apache.catalina.Context;
 import org.apache.catalina.Host;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.Valve;
+import org.apache.catalina.loader.WebappClassLoader;
 import org.apache.catalina.startup.HostConfig;
 import org.apache.catalina.valves.ValveBase;
 import org.apache.tomcat.util.modeler.Registry;
@@ -162,6 +168,14 @@ public class StandardHost
      */
      private boolean createDirs = true;
 
+     
+     /**
+      * Track the class loaders for the child web applications so memory leaks
+      * can be detected.
+      */
+     private Map<ClassLoader, String> childClassLoaders =
+         new WeakHashMap<ClassLoader, String>();
+
     // ------------------------------------------------------------- Properties
 
 
@@ -565,11 +579,42 @@ public class StandardHost
             throw new IllegalArgumentException
                 (sm.getString("standardHost.notContext"));
         super.addChild(child);
-
+        
+        // Record a reference to the context's class loader to aid memory leak
+        // detection
+        if (child.getLoader() != null) {
+            childClassLoaders.put(child.getLoader().getClassLoader(),
+                    child.getName());
+        }
     }
 
 
     /**
+     * Attempt to identify the contexts that have a class loader memory leak.
+     * This is usually triggered on context reload. Note: This method attempts
+     * to force a full garbage collection. This should be used with extreme
+     * caution on a production system.
+     */
+    public String[] findReloadedContextMemoryLeaks() {
+        
+        System.gc();
+        
+        List<String> result = new ArrayList<String>();
+        
+        for (Map.Entry<ClassLoader, String> entry :
+                childClassLoaders.entrySet()) {
+            ClassLoader cl = entry.getKey();
+            if (cl instanceof WebappClassLoader) {
+                if (!((WebappClassLoader) cl).isStarted()) {
+                    result.add(entry.getValue());
+                }
+            }
+        }
+        
+        return result.toArray(new String[result.size()]);
+    }
+
+    /**
      * Return the set of alias names for this Host.  If none are defined,
      * a zero length array is returned.
      */
index 83eaae5..7e144e5 100644 (file)
     <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
     <operation name="init" description="Init" impact="ACTION" returnType="void" />
     <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+    
+    <operation name="findReloadedContextMemoryLeaks"
+               description="Provide a list of contexts that have leaked memory on reload. This will attempt to force a full garbage collection. Use with extreme caution on prouction systems."
+               impact="ACTION"
+               returnType="[Ljava.lang.String;" />
+
   </mbean>
   
   <mbean name="StandardHostValve"
index 4aaa08c..88a65f5 100644 (file)
@@ -1661,6 +1661,10 @@ public class WebappClassLoader
     }
 
 
+    public boolean isStarted() {
+        return started;
+    }
+
     /**
      * Stop the class loader.
      *