You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ja...@apache.org on 2010/10/28 12:48:27 UTC

svn commit: r1028255 - in /myfaces/core/trunk/impl/src/main/java/org/apache/myfaces: view/facelets/tag/MetaRulesetImpl.java webapp/AbstractFacesInitializer.java

Author: jakobk
Date: Thu Oct 28 10:48:26 2010
New Revision: 1028255

URL: http://svn.apache.org/viewvc?rev=1028255&view=rev
Log:
MYFACES-2942 Memory Leak in MyFaces 2.0.1 probably as well in 2.0.2 (use static WeakHashMap<ClassLoader, Map<String, MetadataTarget>> as cache and do a cleanup upon undeploy)

Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java?rev=1028255&r1=1028254&r2=1028255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/MetaRulesetImpl.java Thu Oct 28 10:48:26 2010
@@ -18,9 +18,9 @@
  */
 package org.apache.myfaces.view.facelets.tag;
 
+import org.apache.myfaces.shared_impl.util.ClassUtils;
 import org.apache.myfaces.view.facelets.util.ParameterCheck;
 
-import javax.faces.context.FacesContext;
 import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.MetaRule;
 import javax.faces.view.facelets.MetaRuleset;
@@ -34,6 +34,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.WeakHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -49,22 +50,35 @@ public final class MetaRulesetImpl exten
     //private final static Logger log = Logger.getLogger("facelets.tag.meta");
     private final static Logger log = Logger.getLogger(MetaRulesetImpl.class.getName());
 
-    private static final String METADATA_KEY
-            = "org.apache.myfaces.view.facelets.tag.MetaRulesetImpl.METADATA";
+    /**
+     * Cache the MetadataTarget instances per ClassLoader using the Class-Name of the type variable
+     * of MetadataTarget.
+     * NOTE that we do it this way, because the only other valid way in order to support a shared
+     * classloader scenario would be to use a WeakHashMap<Class<?>, MetadataTarget>, but this
+     * creates a cyclic reference between the key and the value of the WeakHashMap which will
+     * most certainly cause a memory leak! Furthermore we can manually cleanup the Map when
+     * the webapp is undeployed just by removing the Map for the current ClassLoader. 
+     */
+    private final static WeakHashMap<ClassLoader, Map<String, MetadataTarget>> _metadata
+            = new WeakHashMap<ClassLoader, Map<String, MetadataTarget>>();
+
+    /**
+     * Removes the cached MetadataTarget instances in order to prevent a memory leak.
+     */
+    public static void clearMetadataTargetCache()
+    {
+        _metadata.remove(ClassUtils.getContextClassLoader());
+    }
 
     private static Map<String, MetadataTarget> getMetaData()
     {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        Map<String, Object> applicationMap = facesContext
-                .getExternalContext().getApplicationMap();
-
-        Map<String, MetadataTarget> metadata =
-                (Map<String, MetadataTarget>) applicationMap.get(METADATA_KEY);
+        Map<String, MetadataTarget> metadata = (Map<String, MetadataTarget>)
+                _metadata.get(ClassUtils.getContextClassLoader());
 
         if (metadata == null)
         {
             metadata = new HashMap<String, MetadataTarget>();
-            applicationMap.put(METADATA_KEY, metadata);
+            _metadata.put(ClassUtils.getContextClassLoader(), metadata);
         }
 
         return metadata;

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java?rev=1028255&r1=1028254&r2=1028255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java Thu Oct 28 10:48:26 2010
@@ -31,6 +31,7 @@ import org.apache.myfaces.shared_impl.co
 import org.apache.myfaces.shared_impl.util.StateUtils;
 import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
 import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
+import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
 
 import javax.el.ExpressionFactory;
 import javax.faces.application.Application;
@@ -272,6 +273,9 @@ public abstract class AbstractFacesIniti
         
         _dispatchApplicationEvent(servletContext, PreDestroyApplicationEvent.class);
 
+        // clear the cache of MetaRulesetImpl in order to prevent a memory leak
+        MetaRulesetImpl.clearMetadataTargetCache();
+
         // TODO is it possible to make a real cleanup?
     }