geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject svn commit: r180322 - in /geronimo/trunk/modules: axis/src/java/org/apache/geronimo/axis/server/ client/src/java/org/apache/geronimo/client/ connector/src/java/org/apache/geronimo/connector/outbound/ core/src/java/org/apache/geronimo/pool/ deploy-tool/src/java/org/apache/geronimo/deployment/ kernel/src/java/org/apache/geronimo/kernel/config/
Date Mon, 06 Jun 2005 15:19:00 GMT
Author: dain
Date: Mon Jun  6 08:18:59 2005
New Revision: 180322

URL: http://svn.apache.org/viewcvs?rev=180322&view=rev
Log:
Fixed several memory leaks around class loaders not being garbage collected

Modified:
    geronimo/trunk/modules/axis/src/java/org/apache/geronimo/axis/server/AxisWebServiceContainer.java
    geronimo/trunk/modules/client/src/java/org/apache/geronimo/client/AppClientContainer.java
    geronimo/trunk/modules/connector/src/java/org/apache/geronimo/connector/outbound/TCCLInterceptor.java
    geronimo/trunk/modules/core/src/java/org/apache/geronimo/pool/ThreadPool.java
    geronimo/trunk/modules/deploy-tool/src/java/org/apache/geronimo/deployment/Bootstrap.java
    geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/config/Configuration.java

Modified: geronimo/trunk/modules/axis/src/java/org/apache/geronimo/axis/server/AxisWebServiceContainer.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/axis/src/java/org/apache/geronimo/axis/server/AxisWebServiceContainer.java?rev=180322&r1=180321&r2=180322&view=diff
==============================================================================
--- geronimo/trunk/modules/axis/src/java/org/apache/geronimo/axis/server/AxisWebServiceContainer.java
(original)
+++ geronimo/trunk/modules/axis/src/java/org/apache/geronimo/axis/server/AxisWebServiceContainer.java
Mon Jun  6 08:18:59 2005
@@ -101,62 +101,64 @@
         messageContext.setProperty(REQUEST, req);
         messageContext.setProperty(RESPONSE, res);
 
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
         try {
-            String characterEncoding = (String) requestMessage.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
-            if (characterEncoding != null) {
-                messageContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, characterEncoding);
-            } else {
-                messageContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");
-            }
+            try {
+                String characterEncoding = (String) requestMessage.getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
+                if (characterEncoding != null) {
+                    messageContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, characterEncoding);
+                } else {
+                    messageContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");
+                }
 
 
-            String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
-            if (soapAction != null) {
-                messageContext.setUseSOAPAction(true);
-                messageContext.setSOAPActionURI(soapAction);
-            }
+                String soapAction = req.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
+                if (soapAction != null) {
+                    messageContext.setUseSOAPAction(true);
+                    messageContext.setSOAPActionURI(soapAction);
+                }
 
-            SOAPEnvelope env = requestMessage.getSOAPEnvelope();
-            if (env != null && env.getSOAPConstants() != null) {
-                messageContext.setSOAPConstants(env.getSOAPConstants());
-            }
-            SOAPService service = messageContext.getService();
+                SOAPEnvelope env = requestMessage.getSOAPEnvelope();
+                if (env != null && env.getSOAPConstants() != null) {
+                    messageContext.setSOAPConstants(env.getSOAPConstants());
+                }
+                SOAPService service = messageContext.getService();
+
+                Thread.currentThread().setContextClassLoader(classLoader);
+                service.invoke(messageContext);
 
-            Thread.currentThread().setContextClassLoader(classLoader);
-            service.invoke(messageContext);
+                responseMessage = messageContext.getResponseMessage();
+            } catch (AxisFault fault) {
+                responseMessage = handleFault(fault, res, messageContext);
 
-            responseMessage = messageContext.getResponseMessage();
-        } catch (AxisFault fault) {
-            responseMessage = handleFault(fault, res, messageContext);
-
-        } catch (Exception e) {
-            responseMessage = handleException(messageContext, res, e);
-        }
-        //TODO investigate and fix operation == null!
-        if (messageContext.getOperation() != null) {
-            if (messageContext.getOperation().getMep() == OperationType.ONE_WAY) {
-                // No content, so just indicate accepted
+            } catch (Exception e) {
+                responseMessage = handleException(messageContext, res, e);
+            }
+            //TODO investigate and fix operation == null!
+            if (messageContext.getOperation() != null) {
+                if (messageContext.getOperation().getMep() == OperationType.ONE_WAY) {
+                    // No content, so just indicate accepted
+                    res.setStatusCode(202);
+                    return;
+                } else if (responseMessage == null) {
+                    responseMessage = handleException(messageContext, null, new RuntimeException("No
response for non-one-way operation"));
+                }
+            } else if (responseMessage == null) {
                 res.setStatusCode(202);
                 return;
-            } else if (responseMessage == null) {
-                responseMessage = handleException(messageContext, null, new RuntimeException("No
response for non-one-way operation"));
             }
-        } else if (responseMessage == null) {
-            res.setStatusCode(202);
-            return;
-        }
-        try {
-            SOAPConstants soapConstants = messageContext.getSOAPConstants();
-            String contentType1 = responseMessage.getContentType(soapConstants);
-            res.setContentType(contentType1);
-                // Transfer MIME headers to HTTP headers for response message.
-                MimeHeaders responseMimeHeaders = responseMessage.getMimeHeaders();
-                for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) {
-                    MimeHeader responseMimeHeader = (MimeHeader) i.next();
-                    res.setHeader(responseMimeHeader.getName(),
-                                  responseMimeHeader.getValue());
-                }
-            //TODO discuss this with dims.
+            try {
+                SOAPConstants soapConstants = messageContext.getSOAPConstants();
+                String contentType1 = responseMessage.getContentType(soapConstants);
+                res.setContentType(contentType1);
+                    // Transfer MIME headers to HTTP headers for response message.
+                    MimeHeaders responseMimeHeaders = responseMessage.getMimeHeaders();
+                    for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); )
{
+                        MimeHeader responseMimeHeader = (MimeHeader) i.next();
+                        res.setHeader(responseMimeHeader.getName(),
+                                      responseMimeHeader.getValue());
+                    }
+                //TODO discuss this with dims.
 //                // synchronize the character encoding of request and response
 //                String responseEncoding = (String) messageContext.getProperty(
 //                        SOAPMessage.CHARACTER_SET_ENCODING);
@@ -168,12 +170,15 @@
 //                        log.info(Messages.getMessage("exception00"), e);
 //                    }
 //                }
-                //determine content type from message response
-                contentType = responseMessage.getContentType(messageContext.
-                        getSOAPConstants());
-                responseMessage.writeTo(res.getOutputStream());
-        } catch (Exception e) {
-            log.info(Messages.getMessage("exception00"), e);
+                    //determine content type from message response
+                    contentType = responseMessage.getContentType(messageContext.
+                            getSOAPConstants());
+                    responseMessage.writeTo(res.getOutputStream());
+            } catch (Exception e) {
+                log.info(Messages.getMessage("exception00"), e);
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
         }
     }
 

Modified: geronimo/trunk/modules/client/src/java/org/apache/geronimo/client/AppClientContainer.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/client/src/java/org/apache/geronimo/client/AppClientContainer.java?rev=180322&r1=180321&r2=180322&view=diff
==============================================================================
--- geronimo/trunk/modules/client/src/java/org/apache/geronimo/client/AppClientContainer.java
(original)
+++ geronimo/trunk/modules/client/src/java/org/apache/geronimo/client/AppClientContainer.java
Mon Jun  6 08:18:59 2005
@@ -87,12 +87,12 @@
     public void main(String[] args) throws Exception {
         Thread thread = Thread.currentThread();
 
-        ClassLoader contextClassLoader = thread.getContextClassLoader();
-        thread.setContextClassLoader(classLoader);
+        ClassLoader oldClassLoader = thread.getContextClassLoader();
         TransactionContext oldTransactionContext = transactionContextManager.getContext();
         TransactionContext currentTransactionContext = null;
         Subject oldCurrentCaller = ContextManager.getCurrentCaller();
         try {
+            thread.setContextClassLoader(classLoader);
             ContextManager.setCurrentCaller(defaultSubject);
             jndiContext.startClient(appClientModuleName, kernel, classLoader);
             currentTransactionContext = transactionContextManager.newUnspecifiedTransactionContext();
@@ -109,7 +109,7 @@
         } finally {
             jndiContext.stopClient(appClientModuleName);
 
-            thread.setContextClassLoader(contextClassLoader);
+            thread.setContextClassLoader(oldClassLoader);
             transactionContextManager.setContext(oldTransactionContext);
             currentTransactionContext.commit();
             ContextManager.setCurrentCaller(oldCurrentCaller);

Modified: geronimo/trunk/modules/connector/src/java/org/apache/geronimo/connector/outbound/TCCLInterceptor.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/connector/src/java/org/apache/geronimo/connector/outbound/TCCLInterceptor.java?rev=180322&r1=180321&r2=180322&view=diff
==============================================================================
--- geronimo/trunk/modules/connector/src/java/org/apache/geronimo/connector/outbound/TCCLInterceptor.java
(original)
+++ geronimo/trunk/modules/connector/src/java/org/apache/geronimo/connector/outbound/TCCLInterceptor.java
Mon Jun  6 08:18:59 2005
@@ -34,8 +34,8 @@
     public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
         Thread currentThread = Thread.currentThread();
         ClassLoader oldClassLoader = currentThread.getContextClassLoader();
-        currentThread.setContextClassLoader(classLoader);
         try {
+            currentThread.setContextClassLoader(classLoader);
             next.getConnection(connectionInfo);
         } finally {
             currentThread.setContextClassLoader(oldClassLoader);
@@ -45,8 +45,8 @@
     public void returnConnection(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction)
{
         Thread currentThread = Thread.currentThread();
         ClassLoader oldClassLoader = currentThread.getContextClassLoader();
-        currentThread.setContextClassLoader(classLoader);
         try {
+            currentThread.setContextClassLoader(classLoader);
             next.returnConnection(connectionInfo, connectionReturnAction);
         } finally {
             currentThread.setContextClassLoader(oldClassLoader);

Modified: geronimo/trunk/modules/core/src/java/org/apache/geronimo/pool/ThreadPool.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/core/src/java/org/apache/geronimo/pool/ThreadPool.java?rev=180322&r1=180321&r2=180322&view=diff
==============================================================================
--- geronimo/trunk/modules/core/src/java/org/apache/geronimo/pool/ThreadPool.java (original)
+++ geronimo/trunk/modules/core/src/java/org/apache/geronimo/pool/ThreadPool.java Mon Jun
 6 08:18:59 2005
@@ -28,41 +28,46 @@
  * @version $Rev$ $Date$
  */
 public class ThreadPool implements Executor, GBeanLifecycle {
-
     private PooledExecutor executor;
+    private ClassLoader classLoader;
 
-    private int nextWorkerID = 0;
-
-    public ThreadPool(final int poolSize, final String poolName, final long keepAliveTime,
final ClassLoader classLoader) {
+    public ThreadPool(int poolSize, String poolName, long keepAliveTime, ClassLoader classLoader)
{
         PooledExecutor p = new PooledExecutor(poolSize);
         p.abortWhenBlocked();
         p.setKeepAliveTime(keepAliveTime);
         p.setMinimumPoolSize(poolSize);
-        p.setThreadFactory(new ThreadFactory() {
-            public Thread newThread(Runnable arg0) {
-                Thread thread = new Thread(arg0, poolName + " " + getNextWorkerID());
-                thread.setContextClassLoader(classLoader);
-                return thread;
-            }
-        });
+        p.setThreadFactory(new ThreadPoolThreadFactory(poolName, classLoader));
 
         executor = p;
+        this.classLoader = classLoader;
     }
 
 
     public void execute(Runnable command) throws InterruptedException {
-        executor.execute(command);
-    }
-
-    private synchronized int getNextWorkerID() {
-        return nextWorkerID++;
+        PooledExecutor p;
+        synchronized(this) {
+            p = executor;
+        }
+        if (p == null) {
+            throw new IllegalStateException("ThreadPool has been stopped");
+        }
+        Runnable task = new ContextClassLoaderRunnable(command, classLoader);
+        p.execute(task);
     }
 
     public void doStart() throws Exception {
     }
 
     public void doStop() throws Exception {
-        executor.shutdownNow();
+        PooledExecutor p;
+        synchronized(this) {
+            p = executor;
+            executor = null;
+            classLoader = null;
+        }
+        if (p != null) {
+            p.shutdownNow();
+        }
     }
 
     public void doFail() {
@@ -72,6 +77,57 @@
         }
     }
 
+    private static final class ThreadPoolThreadFactory implements ThreadFactory {
+        private final String poolName;
+        private final ClassLoader classLoader;
+
+        private int nextWorkerID = 0;
+
+        public ThreadPoolThreadFactory(String poolName, ClassLoader classLoader) {
+            this.poolName = poolName;
+            this.classLoader = classLoader;
+        }
+
+        public Thread newThread(Runnable arg0) {
+            Thread thread = new Thread(arg0, poolName + " " + getNextWorkerID());
+            thread.setContextClassLoader(classLoader);
+            return thread;
+        }
+
+        private synchronized int getNextWorkerID() {
+            return nextWorkerID++;
+        }
+    }
+
+    private static final class ContextClassLoaderRunnable implements Runnable {
+        private Runnable task;
+        private ClassLoader classLoader;
+
+        public ContextClassLoaderRunnable(Runnable task, ClassLoader classLoader) {
+            this.task = task;
+            this.classLoader = classLoader;
+        }
+
+        public void run() {
+            Runnable myTask = task;
+            ClassLoader myClassLoader = classLoader;
+
+            // clear fields so they can be garbage collected
+            task = null;
+            classLoader = null;
+
+            if (myClassLoader != null) {
+                // we asumme the thread classloader is already set to our final class loader
+                // because the only to access the thread is wrapped with the Runnable or
via the initial thread pool
+                try {
+                    myTask.run();
+                } finally {
+                    Thread.currentThread().setContextClassLoader(myClassLoader);
+                }
+            }
+        }
+    }
+
     public static final GBeanInfo GBEAN_INFO;
 
     static {
@@ -93,6 +149,4 @@
     public static GBeanInfo getGBeanInfo() {
         return GBEAN_INFO;
     }
-
-
 }

Modified: geronimo/trunk/modules/deploy-tool/src/java/org/apache/geronimo/deployment/Bootstrap.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/deploy-tool/src/java/org/apache/geronimo/deployment/Bootstrap.java?rev=180322&r1=180321&r2=180322&view=diff
==============================================================================
--- geronimo/trunk/modules/deploy-tool/src/java/org/apache/geronimo/deployment/Bootstrap.java
(original)
+++ geronimo/trunk/modules/deploy-tool/src/java/org/apache/geronimo/deployment/Bootstrap.java
Mon Jun  6 08:18:59 2005
@@ -121,8 +121,9 @@
 
     public void bootstrap() throws Exception {
         ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader(Bootstrap.class.getClassLoader());
         try {
+            Thread.currentThread().setContextClassLoader(Bootstrap.class.getClassLoader());
+
             // parse the deployment-system and j2ee-deployer plans
             ConfigurationType deployerSystemConfig = ConfigurationDocument.Factory.parse(new
File(deployerSystemPlan)).getConfiguration();
             ConfigurationType j2eeDeployerConfig = ConfigurationDocument.Factory.parse(new
File(j2eeDeployerPlan)).getConfiguration();

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/config/Configuration.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/config/Configuration.java?rev=180322&r1=180321&r2=180322&view=diff
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/config/Configuration.java
(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/config/Configuration.java
Mon Jun  6 08:18:59 2005
@@ -23,6 +23,7 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
@@ -35,6 +36,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.lang.reflect.Field;
 
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
@@ -129,12 +131,12 @@
     /**
      * The names of all GBeans contained in this configuration.
      */
-    private final Set objectNames;
+    private Set objectNames;
 
     /**
      * The classloadeder used to load the child GBeans contained in this configuration.
      */
-    private final ConfigurationClassLoader configurationClassLoader;
+    private ConfigurationClassLoader configurationClassLoader;
 
     /**
      * The GBeanData for the GBeans contained in this configuration.  These must be persisted
as a ByteArray, becuase
@@ -144,6 +146,21 @@
     private byte[] gbeanState;
 
     /**
+     * Base path used to resolve relative class path entries.
+     */
+    private final URL baseURL;
+
+    /**
+     * Parent of this configuration
+     */
+    private final ConfigurationParent parent;
+
+    /**
+     * The repositories used dependencies.
+     */
+    private final Collection repositories;
+
+    /**
      * Only used to allow declaration as a reference.
      */
     public Configuration() {
@@ -160,6 +177,9 @@
         configurationClassLoader = null;
         dependencies = null;
         classPath = null;
+        baseURL = null;
+        parent = null;
+        repositories = null;
     }
 
     /**
@@ -194,8 +214,11 @@
         this.objectName = JMXUtil.getObjectName(objectName);
         this.id = id;
         this.moduleType = moduleType;
+        this.baseURL = baseURL;
         this.parentId = parentId;
+        this.parent = parent;
         this.gbeanState = gbeanState;
+        this.repositories = repositories;
         if (classPath != null) {
             this.classPath = classPath;
         } else {
@@ -211,7 +234,21 @@
 
         this.domain = domain;
         this.server = server;
+    }
+
+    public String getObjectName() {
+        return objectNameString;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
 
+    public String getServer() {
+        return server;
+    }
+
+    public void doStart() throws Exception {
         // build configurationClassLoader
         URL[] urls = resolveClassPath(classPath, baseURL, dependencies, repositories);
         log.debug("ClassPath for " + id + " resolved to " + Arrays.asList(urls));
@@ -248,7 +285,7 @@
                 log.trace("Registering GBean " + name);
                 kernel.loadGBean(gbeanData, configurationClassLoader);
                 objectNames.add(name);
-                // todo change this to a dependency on the gbeanData itself as soon as we
add that feature 
+                // todo change this to a dependency on the gbeanData itself as soon as we
add that feature
                 kernel.getDependencyManager().addDependency(name, this.objectName);
             }
             this.objectNames = objectNames;
@@ -292,18 +329,6 @@
         return urls;
     }
 
-    public String getObjectName() {
-        return objectNameString;
-    }
-
-    public String getDomain() {
-        return domain;
-    }
-
-    public String getServer() {
-        return server;
-    }
-
     private static void setGBeanBaseUrl(GBeanData gbeanData, URL baseUrl) {
         GBeanInfo gbeanInfo = gbeanData.getGBeanInfo();
         Set attributes = gbeanInfo.getAttributes();
@@ -316,9 +341,6 @@
         }
     }
 
-    public void doStart() throws Exception {
-    }
-
     public void doStop() throws Exception {
         log.info("Stopping configuration " + id);
 
@@ -354,6 +376,15 @@
             }
         }
 
+        // destroy the class loader
+        LogFactory.release(configurationClassLoader);
+        configurationClassLoader = null;
+        clearSoftCache(ObjectInputStream.class, "subclassAudits");
+        clearSoftCache(ObjectOutputStream.class, "subclassAudits");
+        clearSoftCache(ObjectStreamClass.class, "localDescs");
+        clearSoftCache(ObjectStreamClass.class, "reflectors");
+
+        // update the configuation store
         if (configurationStore != null) {
             ConfigurationData configurationData = new ConfigurationData();
             configurationData.setId(id);
@@ -365,6 +396,23 @@
             configurationData.setDependencies(dependencies);
             configurationData.setClassPath(classPath);
             configurationStore.updateConfiguration(configurationData);
+        }
+    }
+
+    private static void clearSoftCache(Class clazz, String fieldName) {
+        Map cache = null;
+        try {
+            Field f = clazz.getDeclaredField(fieldName);
+            f.setAccessible(true);
+            cache = (Map) f.get(null);
+        } catch (Throwable e) {
+            log.error("Unable to clear SoftCache field " + fieldName + " in class " + clazz);
+        }
+
+        if (cache != null) {
+            synchronized (cache) {
+                cache.clear();
+            }
         }
     }
 



Mime
View raw message