Java heap retention in org.apache.jasper.servlet.JspServlet
Environment
- JBoss Application Server 4.0.x
- JBoss Enterprise Application Platform
- 4.2
- 4.3
- JBoss Enterprise Web Server (EWS) 1.0
- Tomcat 5.5
- Tomcat 6.0
Issue
- Experiencing memory issues with the org.apache.jasper.servlet.JspServlet component. It is consistently a high consumer of memory in our heap.
Resolution
- Set the JspServlet development mode to false in JBOSS_HOME/server/CONF/deploy/jboss-web.deployer/confweb.xml (EAP 4.2/4.3) or JBOSS_HOME/server/CONF/deployers/jbossweb.deployer/web.xml (EAP 5) as follows:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>development</param-name> <param-value>false</param-value> </init-param> ... </servlet> - Precompile JSPs so they are executed as plain servlets, thereby avoiding JspServlet. This is a good solution when JSPs do not change between releases.
- Move to Tomcat 7 (EWS 2.0), where functionality was added to the background thread to limit this retention:
https://issues.apache.org/bugzilla/show_bug.cgi?id=48358 - Future versions of JBoss may include the Tomcat 7 functionality:
https://jira.jboss.org/jira/browse/JBWEB-168
Root Cause
JspServlet has a reference called "rctxt" of type JspRuntimeContext. JspRuntimeContext stores JSP page data for compiling updated JSP pages. JspRuntimeContext has a referece called "jsps" of type SynchronizedMap object that holds a collection of JspServletWrapper objects. JspServletWrapper has a reference called "ctx" of type JspCompilationContext, which itself has a reference called "jspCompiler" of type Compiler. The Compiler class has a reference called "pageNodes" of type Node$Nodes. pageNodes is where the parsed representation of the jsp is stored. The source of every JSP is held in memory to provide detailed messages in the event of an error.
When the jsp is compiled, the Compiler.compile() method checks to see if the jspServlet development flag is set to true (the default value). If it is, the pageNodes will not be cleared at the end of the Compile.compile() method:
// Only get rid of the pageNodes if in production.
// In development mode, they are used for detailed
// error messages.
// http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
if(!this.options.getDevelopment()) {
pageNodes = null;
}
Diagnostic Steps
- Get a heap dump and analyze it:
- Verify the JspServlet retention is related to many JspServletWrapper objects stored in the "jsps" SynchronizedMap in the "rctxt" JspRuntimeContext reference held by JspServlet. See attached JspServlet-retention.png.
- Check to see if the JspServlet development mode is on. It is on by default, so unless it is set to false in
JBOSS_HOME/server/CONF/deploy/jboss-web.deployer/confweb.xml(EAP 4.2/4.3) orJBOSS_HOME/server/CONF/deployers/jbossweb.deployer/web.xml(EAP 5), it will be enabled. This can be verified in the heap dump with the following query:
select j.development from org.jboss.web.tomcat.service.jasper.JspServletOptions
The query for EAP 6 is:SELECT j.development FROM org.apache.jasper.EmbeddedServletOptions
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.