https://bz.apache.org/bugzilla/show_bug.cgi?id=58486
Bug ID: 58486
Summary: JreMemoryLeakPreventionListener: initialize two
further JRE classes
Product: Tomcat 8
Version: trunk
Hardware: PC
Status: NEW
Severity: minor
Priority: P2
Component: Catalina
Assignee: [email protected]
Reporter: [email protected]
I would like to propose adding a further couple of classes to those that
Tomcat's JreMemoryLeakPreventionListener statically initializes.
The classes com.sun.org.apache.xerces.internal.dom.DOMNormalizer and
com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl, both within
rt.jar, each contain a static final field of type RuntimeException named
'abort'. When these classes are statically initialized, these exceptions are
created and their stacktraces filled in. If a web app class happens to be in
the call stack when either class's exception is created, this class cannot then
be garbage collected when the web app is stopped because an exception in a
static field of a class has a reference to it. This then causes a PermGen leak
as the web apps's classloader, and all of the classes it loaded, cannot be
garbage-collected.
To reproduce this issue, use the following servlet class:
package com.example;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.ls.DOMImplementationLS;
public class DOMNormalizerLeakServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException {
try {
Document document =
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
document.createElement("test");
DOMImplementationLS implementation =
(DOMImplementationLS)document.getImplementation();
implementation.createLSSerializer().writeToString(document);
response.getWriter().write("done");
}
catch (Exception e) {
throw new ServletException(e);
}
}
}
and the following web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>com.example.DOMNormalizerLeakServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
</web-app>
I've reproduced this problem with the latest Tomcat (8.0.27) and the latest
Oracle JDK8 (1.8.0_60), by:
* deploying a web app consisting of the above servlet class and deployment
descriptor to Tomcat,
* viewing the index.html page generated by Tomcat (the browser should show the
word 'done'),
* reloading the web app using the Tomcat manager app,
* clicking the 'Find leaks' button in the Diagnostics section of the manager
app, which reveals a possible memory leak,
* using a profiler such as JVisualVM to confirm that Tomcat now has a
'destroyed' classloader that could not be garbage collected because there is a
chain of references from a JRE class to the servlet class it loaded.
Here's a path from the classloader to the exception, which I obtained with the
help of JVisualVM:
this - value: org.apache.catalina.loader.WebappClassLoader #3
<- <classLoader> - class: com.example.DOMNormalizerLeakServlet, value:
org.apache.catalina.loader.WebappClassLoader #3
<- [2] - class: java.lang.Object[], value:
com.example.DOMNormalizerLeakServlet class DOMNormalizerLeakServlet
<- [2] - class: java.lang.Object[], value: java.lang.Object[] #4319
<- backtrace - class: java.lang.RuntimeException, value:
java.lang.Object[] #4318
<- abort (sticky class) - class:
com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl, value:
java.lang.RuntimeException #1
There is a straightforward workaround for this: add the names of these two
classes to the classesToInitialize attribute for the
JreMemoryLeakPreventionListener. This then causes the classes to be statically
initialized by Tomcat itself and keeps web app classes out of the stacktrace of
these exceptions.
I have filed a bug report with Oracle to change the behaviour of these two
classes. However, until this gets fixed (if it gets fixed at all), it would be
appreciated if the JreMemoryLeakPreventionListener could be adapted to handle
these two classes.
--
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]