Author: remm
Date: Sat Nov 12 09:48:54 2005
New Revision: 332801

URL: http://svn.apache.org/viewcvs?rev=332801&view=rev
Log:
- Add additional experimental measures against apparent garbage collection bugs
  by setting to null static final fields. Also unregister any JDBC driver.
  This code is based on techniques found on the Hibernate forums, where this
  sort of cleanup proved to be able to fix memory leaking.
- According to Hibernate developers, the following scenario is causing a
  leak of the classloader (note: obviously this is not a Tomcat bug, but
  merely something where there seems to be a workaround):

public class DeployTestServlet extends HttpServlet {
     private TestValue testValue;
     public void init(ServletConfig servletConfig) throws ServletException {
         super.init(servletConfig);
         testValue = TestHolder.TEST_VALUE;
     }
}

public class TestHolder {
     public static final TestValue TEST_VALUE = new TestValue(); }

public class TestValue {
     private transient ClassLoader value;
     public TestValue() {
         value = this.getClass().getClassLoader();
     }
}

Modified:
    
tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java

Modified: 
tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
URL: 
http://svn.apache.org/viewcvs/tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java?rev=332801&r1=332800&r2=332801&view=diff
==============================================================================
--- 
tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
 (original)
+++ 
tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
 Sat Nov 12 09:48:54 2005
@@ -23,6 +23,8 @@
 import java.io.FilePermission;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -33,6 +35,9 @@
 import java.security.PermissionCollection;
 import java.security.Policy;
 import java.security.PrivilegedAction;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -1470,20 +1475,9 @@
      */
     public void stop() throws LifecycleException {
 
-        /*
-         * Clear the IntrospectionUtils cache.
-         *
-         * Implementation note:
-         * Any reference to IntrospectionUtils which may cause the static
-         * initalizer of that class to be invoked must occur prior to setting
-         * the started flag to FALSE, because the static initializer of
-         * IntrospectionUtils makes a call to
-         * org.apache.commons.logging.LogFactory.getLog(), which ultimately
-         * calls the loadClass() method of the thread context classloader,
-         * which is the same as this classloader, whose impl throws a
-         * ThreadDeath if the started flag has been set to FALSE.
-         */
-        IntrospectionUtils.clear();
+        // Clearing references should be done before setting started to
+        // false, due to possible side effects
+        clearReferences();
 
         started = false;
 
@@ -1526,11 +1520,6 @@
             deleteDir(loaderDir);
         }
 
-        // Clear the classloader reference in common-logging
-        org.apache.commons.logging.LogFactory.release(this);
-        // Clear the classloader reference in the VM's bean introspector
-        java.beans.Introspector.flushCaches();
-
     }
 
 
@@ -1561,6 +1550,61 @@
 
     // ------------------------------------------------------ Protected Methods
 
+    
+    /**
+     * Clear references.
+     */
+    protected void clearReferences() {
+
+        // Unregister any JDBC drivers loaded by this classloader
+        Enumeration drivers = DriverManager.getDrivers();
+        while (drivers.hasMoreElements()) {
+            Driver driver = (Driver) drivers.nextElement();
+            if (driver.getClass().getClassLoader() == this) {
+                try {
+                    DriverManager.deregisterDriver(driver);
+                } catch (SQLException e) {
+                    log.warn("SQL driver deregistration failed", e);
+                }
+            }
+        }
+        
+        // Null out any static or final fields from loaded classes,
+        // as a workaround for apparent garbage collection bugs
+        Iterator loadedClasses = resourceEntries.values().iterator();
+        while (loadedClasses.hasNext()) {
+            ResourceEntry entry = (ResourceEntry) loadedClasses.next();
+            if (entry.loadedClass != null) {
+                Field[] fields = entry.loadedClass.getDeclaredFields();
+                for (int i = 0; i < fields.length; i++) {
+                    Field field = fields[i];
+                    int mods = field.getModifiers();
+                    if (!(!Modifier.isStatic(mods) || !Modifier.isFinal(mods) 
+                            || field.getType().isPrimitive() 
+                            || field.getName().indexOf("$") != -1)) {
+                        field.setAccessible(true);
+                        try {
+                            field.set(null, null);
+                        } catch (Exception e) {
+                            log.info("Could not set field " + field.getName() 
+                                    + " to null in class " + 
entry.loadedClass.getName(), e);
+                        }
+                    }
+                }
+            }
+        }
+        
+         // Clear the IntrospectionUtils cache.
+        IntrospectionUtils.clear();
+        
+        // Clear the classloader reference in common-logging
+        org.apache.commons.logging.LogFactory.release(this);
+        
+        // Clear the classloader reference in the VM's bean introspector
+        java.beans.Introspector.flushCaches();
+
+    }
+    
 
     /**
      * Used to periodically signal to the classloader to release JAR resources.



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to