Bug 50460 - First access to a jspx page causes classloader leak in JspDocumentParser
First access to a jspx page causes classloader leak in JspDocumentParser
Status: RESOLVED FIXED
Product: Tomcat 6
Classification: Unclassified
Component: Jasper
6.0.29
PC Windows XP
: P2 normal (vote)
: default
Assigned To: Tomcat Developers Mailing List
:
Depends on:
Blocks:
  Show dependency tree
 
Reported: 2010-12-11 21:33 UTC by Konstantin Kolinko
Modified: 2011-01-20 12:21 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Konstantin Kolinko 2010-12-11 21:33:47 UTC
Running latest 6.0.x,

To reproduce:
1. Stop Tomcat
2. Deploy the examples webapp
3. Create /webapps/examples/foo.jsp file containing the following text:
<jsp:include page="/jsp/jsp2/jspx/basic.jspx"/>

4. Make sure that the work folder of Tomcat is empty.
5. Start Tomcat
6. Go to http://localhost:8080/examples/foo.jsp
7. Go to the Manager web application and stop the examples webapp.
8. Press the "Find leaks" button there.
ACTUAL RESULT:
It is reported that "/examples" causes a leak.
EXPECTED RESULT:
No leaks.

This issue is apparently caused by an instance of org.apache.jasper.compiler.JspDocumentParser$EnableDTDValidationException
that is being kept in a static final field.

More discussion of such leaks can be found in thread [1] on dev@.

[1] http://tomcat.markmail.org/thread/v4xmg5v5t6oa4mrs
http://marc.info/?l=tomcat-dev&m=129211856426188&w=2

Additional comments:
1) This issue affects the first request that loads the JspDocumentParser class. Subsequent requests do not cause the issue. Thus only a single webapp is affected.
2) The issue does not happen when there is no webapp code in the call stack. I.e., it does not happen if the JSPX page was requested directly.
That is why the reproduction recipe uses <jsp:include/>.

Possible solutions:
1) Preload the JspDocumentParser class when Tomcat starts.
2) Do not cache the Exception. Create a new instance each time.
3) Override the fillInStackTrace() method, like it was done in AbstractDOMParser$Abort in Apache Xerces [2]. I do not know, whether that helps or not.

[2] http://svn.apache.org/viewvc/xerces/java/trunk/src/org/apache/xerces/parsers/AbstractDOMParser.java?annotate=782187#l162
Comment 1 Sylvain Laurent 2010-12-12 16:31:14 UTC
Waw, that's a nice bug in the JVM !

To avoid it in tomcat, I vote for 2) Do not cache the Exception. Create a new instance each time.
Comment 2 Mark Thomas 2010-12-12 16:38:47 UTC
2 gets my vote
Comment 3 Sylvain Laurent 2010-12-12 16:55:34 UTC
I found another place where the same type of leak might occur : in ProxyDirContext (in tc7, I dod not check with tc6), there is 

    protected static final NameNotFoundException NOT_FOUND_EXCEPTION =
        new ImmutableNameNotFoundException();

In this case the stack does not contain webapp code, so there's no leak of webapp classloader.
But there can be a leak of tomcat's classloader if it is embedded...
Comment 4 Konstantin Kolinko 2010-12-12 20:20:49 UTC
Fixed in trunk in r1044987 and will be in 7.0.6.
I will propose it for 6.0 and 5.5.

I should note, that 3) fixes the issue in my environment.

For the JspDocumentParser$EnableDTDValidationException class I am using 2) as the fix and 3) for sake of performance.

For the ImmutableNameNotFoundException class I am using 3), as 2) would be too much of a change for me.

(In reply to comment #3)
> But there can be a leak of tomcat's classloader if it is embedded...

ProxyDirContext is loaded by the Tomcat's classloader as well, and thus it static field should be GC'able at the same time as the Tomcat classes that might appear in the stacktrace there. So I do not think that there will be an observable leak with ProxyDirContext.
Comment 5 Christopher Schultz 2010-12-14 14:25:07 UTC
FWIW, I still vote #2. I'm pretty sure that actually throwing the exception is more costly than creating the Exception object.
Comment 6 Mark Thomas 2011-01-05 09:00:07 UTC
Fixed in 6.0.x and will be included in 6.0.30 onwards.
Comment 7 Mark Thomas 2011-01-20 12:21:53 UTC
Fixed in 5.5.x and will be included in 5.5.32 onwards.