Bug 30136

Summary: Memory leak in JSTL ELEvaluator cache
Product: Taglibs Reporter: Knut Forkalsrud <knut>
Component: Standard TaglibAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED DUPLICATE    
Severity: normal CC: dgantenbein
Priority: P3    
Version: 1.0.4   
Target Milestone: ---   
Hardware: All   
OS: All   

Description Knut Forkalsrud 2004-07-16 01:32:13 UTC
We're using version 1.0.2, but the source code for newer releases have no change
in this area.  The problem is the expression evaluator:

jakarta-taglibs/standard/src/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java

By default it sets up a hash map to cache the values of each expression it
evaluates, but there is no upper limit on how large the cache is allowed to
grow.  In our case the application grows approx 500 MByte in a 24 hour period. 
I have searched for other mentionings of the same problem and found only one:

http://www.mail-archive.com/taglibs-user@jakarta.apache.org/msg07007.html

For now I have set up a bit of a hack to work around the issue.  Since there is
no easy way to access this class from outside the package I had to make a new
class in a package with the same name.  This is a subclass of
java.util.LinkedHashMap that won't grow indefinitely.  I just swap it in
replacing the existing ELEvaluator.sCachedExpressionStrings

I think the standard cache in ELEvaluatorCache should have an upper size limit.





import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.jsp.JspException;
import org.apache.log4j.Logger;

/**
 * @author Knut Forkalsrud
 */
public class EvaluatorCache
    extends LinkedHashMap
{
    int maxEntries;

    public EvaluatorCache(int maxEntries) {
        super((int)((float)maxEntries / 0.75), (float)0.75, true);
        this.maxEntries = maxEntries;
    }

    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > maxEntries;
    }

    public static void replaceCacheImpl(int maxEntries) {
        ELEvaluator.sCachedExpressionStrings
            = Collections.synchronizedMap(new EvaluatorCache(maxEntries));
    }
}

// eof
Comment 1 Dhiru Pandey 2005-02-23 19:35:06 UTC

*** This bug has been marked as a duplicate of 31789 ***