You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by da...@apache.org on 2007/10/16 08:10:54 UTC

svn commit: r585052 - in /openejb/trunk/openejb3: ./ container/openejb-core/src/main/java/org/apache/openejb/ container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ server/openejb-client/src/main/java/org/apache/openejb/client/

Author: dain
Date: Mon Oct 15 23:10:53 2007
New Revision: 585052

URL: http://svn.apache.org/viewvc?rev=585052&view=rev
Log:
fixed some memory leaks in Client EJBInvocationHandler and with Sun vm class loader caches
upgraded to commons-logging 1.1 which reduces class loader leaks

Modified:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
    openejb/trunk/openejb3/pom.xml
    openejb/trunk/openejb3/server/openejb-client/src/main/java/org/apache/openejb/client/EJBInvocationHandler.java

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java?rev=585052&r1=585051&r2=585052&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java Mon Oct 15 23:10:53 2007
@@ -17,16 +17,63 @@
  */
 package org.apache.openejb;
 
+import java.beans.Introspector;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Map;
+
 /**
  * @version $Revision$ $Date$
  */
 public class ClassLoaderUtil {
 
     public static ClassLoader getContextClassLoader() {
-        return (ClassLoader) java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
-            public Object run() {
+        return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+            public ClassLoader run() {
                 return Thread.currentThread().getContextClassLoader();
             }
         });
+    }
+
+    /**
+     * Cleans well known class loader leaks in VMs and libraries.  There is a lot of bad code out there and this method
+     * will clear up the know problems.  This method should only be called when the class loader will no longer be used.
+     * It this method is called two often it can have a serious impact on preformance.
+     * @param classLoader the class loader to destroy
+     */
+    public static void clearClassLoaderCaches() {
+        clearSunSoftCache(ObjectInputStream.class, "subclassAudits");
+        clearSunSoftCache(ObjectOutputStream.class, "subclassAudits");
+        clearSunSoftCache(ObjectStreamClass.class, "localDescs");
+        clearSunSoftCache(ObjectStreamClass.class, "reflectors");
+        Introspector.flushCaches();
+    }
+
+    /**
+     * Clears the caches maintained by the SunVM object stream implementation.  This method uses reflection and
+     * setAccessable to obtain access to the Sun cache.  The cache is locked with a synchronize monitor and cleared.
+     * This method completely clears the class loader cache which will impact preformance of object serialization.
+     * @param clazz the name of the class containing the cache field
+     * @param fieldName the name of the cache field
+     */
+    public static void clearSunSoftCache(Class clazz, String fieldName) {
+        Map cache = null;
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            cache = (Map) field.get(null);
+        } catch (Throwable ignored) {
+            // there is nothing a user could do about this anyway
+        }
+
+        if (cache != null) {
+            synchronized (cache) {
+                cache.clear();
+            }
+        }
     }
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=585052&r1=585051&r2=585052&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java Mon Oct 15 23:10:53 2007
@@ -26,6 +26,7 @@
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.UndeployException;
 import org.apache.openejb.BeanType;
+import org.apache.openejb.ClassLoaderUtil;
 import org.apache.openejb.resource.GeronimoConnectionManagerFactory;
 import org.apache.openejb.core.ConnectorReference;
 import org.apache.openejb.core.CoreContainerSystem;
@@ -665,6 +666,9 @@
                 undeployException.getCauses().add(new Exception("client: " + clientId + ": " + t.getMessage(), t));
             }
         }
+
+        ClassLoaderUtil.clearClassLoaderCaches();
+
         if (undeployException.getCauses().size() > 0) {
             throw undeployException;
         }

Modified: openejb/trunk/openejb3/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/pom.xml?rev=585052&r1=585051&r2=585052&view=diff
==============================================================================
--- openejb/trunk/openejb3/pom.xml (original)
+++ openejb/trunk/openejb3/pom.xml Mon Oct 15 23:10:53 2007
@@ -357,12 +357,12 @@
       <dependency>
         <groupId>commons-logging</groupId>
         <artifactId>commons-logging-api</artifactId>
-        <version>1.0.4</version>
+        <version>1.1</version>
       </dependency>
       <dependency>
         <groupId>commons-logging</groupId>
         <artifactId>commons-logging</artifactId>
-        <version>1.0.4</version>
+        <version>1.1</version>
       </dependency>
       <dependency>
         <groupId>hsqldb</groupId>

Modified: openejb/trunk/openejb3/server/openejb-client/src/main/java/org/apache/openejb/client/EJBInvocationHandler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/server/openejb-client/src/main/java/org/apache/openejb/client/EJBInvocationHandler.java?rev=585052&r1=585051&r2=585052&view=diff
==============================================================================
--- openejb/trunk/openejb3/server/openejb-client/src/main/java/org/apache/openejb/client/EJBInvocationHandler.java (original)
+++ openejb/trunk/openejb3/server/openejb-client/src/main/java/org/apache/openejb/client/EJBInvocationHandler.java Mon Oct 15 23:10:53 2007
@@ -18,12 +18,14 @@
 
 import java.io.Serializable;
 import java.lang.reflect.Method;
+import java.lang.ref.WeakReference;
 import java.rmi.NoSuchObjectException;
 import java.rmi.RemoteException;
 import java.rmi.AccessException;
-import java.rmi.Remote;
 import java.util.HashSet;
-import java.util.Hashtable;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.openejb.client.proxy.InvocationHandler;
 
@@ -31,7 +33,6 @@
 import javax.transaction.TransactionRolledbackException;
 import javax.ejb.TransactionRequiredLocalException;
 import javax.ejb.TransactionRolledbackLocalException;
-import javax.ejb.NoSuchObjectLocalException;
 import javax.ejb.AccessLocalException;
 import javax.ejb.EJBException;
 import javax.ejb.EJBAccessException;
@@ -45,7 +46,7 @@
     protected static final Method HASHCODE = getMethod(Object.class, "hashCode");
     protected static final Method TOSTRING = getMethod(Object.class, "toString");
 
-    protected static final Hashtable<Object,HashSet> liveHandleRegistry = new Hashtable();
+    protected static final ConcurrentMap<Object, Set<WeakReference<EJBInvocationHandler>>> liveHandleRegistry = new ConcurrentHashMap<Object, Set<WeakReference<EJBInvocationHandler>>>();
 
     protected transient boolean inProxyMap = false;
 
@@ -145,27 +146,32 @@
 
     protected static void invalidateAllHandlers(Object key) {
 
-        HashSet<EJBInvocationHandler> set = liveHandleRegistry.remove(key);
+        Set<WeakReference<EJBInvocationHandler>> set = liveHandleRegistry.remove(key);
         if (set == null) return;
 
         synchronized (set) {
-            for (EJBInvocationHandler handler : set) {
-                handler.invalidateReference();
+            for (WeakReference<EJBInvocationHandler> ref : set) {
+                EJBInvocationHandler handler = ref.get();
+                if (handler != null) {
+                    handler.invalidateReference();
+                }
             }
             set.clear();
         }
     }
 
     protected static void registerHandler(Object key, EJBInvocationHandler handler) {
-        HashSet set = (HashSet) liveHandleRegistry.get(key);
+        Set<WeakReference<EJBInvocationHandler>> set = liveHandleRegistry.get(key);
 
         if (set == null) {
-            set = new HashSet();
-            liveHandleRegistry.put(key, set);
+            set = new HashSet<WeakReference<EJBInvocationHandler>>();
+            Set<WeakReference<EJBInvocationHandler>> current = liveHandleRegistry.putIfAbsent(key, set);
+            // someone else added the set
+            if (current != null) set = current;
         }
 
         synchronized (set) {
-            set.add(handler);
+            set.add(new WeakReference<EJBInvocationHandler>(handler));
         }
     }