Author: markt
Date: Wed Feb 24 00:07:06 2010
New Revision: 915603
URL: http://svn.apache.org/viewvc?rev=915603&view=rev
Log:
Add basic memory leak detection for JMX and manager (kkolinko/markt)
Modified:
tomcat/tc6.0.x/trunk/STATUS.txt
tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardHost.java
tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/LocalStrings.properties
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/ManagerServlet.java
tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
tomcat/tc6.0.x/trunk/webapps/docs/html-manager-howto.xml
tomcat/tc6.0.x/trunk/webapps/docs/manager-howto.xml
tomcat/tc6.0.x/trunk/webapps/manager/WEB-INF/web.xml
Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Wed Feb 24 00:07:06 2010
@@ -118,36 +118,6 @@
http://tools.ietf.org/html/rfc2616
-
-* Memory leak detection for JMX and manager
-
http://people.apache.org/~kkolinko/patches/2010-02-16_tc6_memory-leak-detection.patch
- It is corrected markt's patch
- (Added revs.909204,910584,910612
- TC 6 specifics: /findleaks should be explicitly mapped in web.xml,
- where TC 7 uses /text/findleaks, and that URL is mentioned in
manager-howto.xml)
- +1: kkolinko, fhanik, markt
- -1:
-
- kkolinko: Some further thoughts on naming/messages/documentation
- - It might be not so clear to a newcomer, that to use this functionality
you have
- a) Use you application
- b) Reload it
- c) Press the "Find leaks" button
- It does not work without a) and b).
-
- - Saying that application "triggered" a memory leak sounds too harsh for
- me. I think "has" or "suffered" would be better here.
-
- - It is safe to press the "Find leaks" button several times. Besides the
- gc call it just "lists" the contexts that are still present in memory.
- It does not clear its own list.
-
- kkolinko: The display fix for ROOT context (r910612) might be applied to
- StandardHost.findReloadedContextMemoryLeaks() as well. Any comments? If
- results of a JMX call are displayed to humans, I'd be better to have "/"
- instead of an empty string.
-
-
* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48371
Take account of comments when working out where to insert generated web.xml
http://people.apache.org/~markt/patches/2010-02-13-bug48371.patch
Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardHost.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardHost.java?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardHost.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardHost.java Wed
Feb 24 00:07:06 2010
@@ -19,14 +19,23 @@
package org.apache.catalina.core;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Valve;
+import org.apache.catalina.loader.WebappClassLoader;
import org.apache.catalina.startup.HostConfig;
import org.apache.catalina.valves.ValveBase;
import org.apache.tomcat.util.modeler.Registry;
@@ -164,6 +173,12 @@
*/
private boolean xmlNamespaceAware = false;
+ /**
+ * Track the class loaders for the child web applications so memory leaks
+ * can be detected.
+ */
+ private Map<ClassLoader, String> childClassLoaders =
+ new WeakHashMap<ClassLoader, String>();
// ------------------------------------------------------------- Properties
@@ -520,6 +535,11 @@
*/
public void addChild(Container child) {
+ if (child instanceof Lifecycle) {
+ ((Lifecycle) child).addLifecycleListener(
+ new MemoryLeakTrackingListener());
+ }
+
if (!(child instanceof Context))
throw new IllegalArgumentException
(sm.getString("standardHost.notContext"));
@@ -529,6 +549,49 @@
/**
+ * Used to ensure the regardless of {...@link Context} implementation, a
record
+ * is kept of the class loader used every time a context starts.
+ */
+ private class MemoryLeakTrackingListener implements LifecycleListener {
+
+ public void lifecycleEvent(LifecycleEvent event) {
+ if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
+ if (event.getSource() instanceof Context) {
+ Context context = ((Context) event.getSource());
+ childClassLoaders.put(context.getLoader().getClassLoader(),
+ context.getServletContext().getContextPath());
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Attempt to identify the contexts that have a class loader memory leak.
+ * This is usually triggered on context reload. Note: This method attempts
+ * to force a full garbage collection. This should be used with extreme
+ * caution on a production system.
+ */
+ public String[] findReloadedContextMemoryLeaks() {
+
+ System.gc();
+
+ List<String> result = new ArrayList<String>();
+
+ for (Map.Entry<ClassLoader, String> entry :
+ childClassLoaders.entrySet()) {
+ ClassLoader cl = entry.getKey();
+ if (cl instanceof WebappClassLoader) {
+ if (!((WebappClassLoader) cl).isStarted()) {
+ result.add(entry.getValue());
+ }
+ }
+ }
+
+ return result.toArray(new String[result.size()]);
+ }
+
+ /**
* Return the set of alias names for this Host. If none are defined,
* a zero length array is returned.
*/
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
Wed Feb 24 00:07:06 2010
@@ -542,6 +542,12 @@
<operation name="stop" description="Stop" impact="ACTION"
returnType="void" />
<operation name="init" description="Init" impact="ACTION"
returnType="void" />
<operation name="destroy" description="Destroy" impact="ACTION"
returnType="void" />
+
+ <operation name="findReloadedContextMemoryLeaks"
+ description="Provide a list of contexts that have leaked memory
on reload. This will attempt to force a full garbage collection. Use with
extreme caution on production systems."
+ impact="ACTION"
+ returnType="[Ljava.lang.String;" />
+
</mbean>
<mbean name="StandardHostValve"
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java
Wed Feb 24 00:07:06 2010
@@ -1642,6 +1642,10 @@
}
+ public boolean isStarted() {
+ return started;
+ }
+
/**
* Stop the class loader.
*
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
(original)
+++
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java
Wed Feb 24 00:07:06 2010
@@ -136,6 +136,8 @@
message = start(path);
} else if (command.equals("/stop")) {
message = stop(path);
+ } else if (command.equals("/findleaks")) {
+ message = findleaks();
} else {
message =
sm.getString("managerServlet.unknownCommand", command);
@@ -498,6 +500,16 @@
args[3] = sm.getString("htmlManagerServlet.deployButton");
writer.print(MessageFormat.format(UPLOAD_SECTION, args));
+ // Diagnostics section
+ args = new Object[5];
+ args[0] = sm.getString("htmlManagerServlet.diagnosticsTitle");
+ args[1] = sm.getString("htmlManagerServlet.diagnosticsLeak");
+ args[2] = response.encodeURL(request.getContextPath() +
+ "/html/findleaks");
+ args[3] = sm.getString("htmlManagerServlet.diagnosticsLeakWarning");
+ args[4] = sm.getString("htmlManagerServlet.diagnosticsLeakButton");
+ writer.print(MessageFormat.format(DIAGNOSTICS_SECTION, args));
+
// Server Header Section
args = new Object[7];
args[0] = sm.getString("htmlManagerServlet.serverTitle");
@@ -631,6 +643,33 @@
return stringWriter.toString();
}
+
+ /**
+ * Find potential memory leaks caused by web application reload.
+ *
+ * @see ManagerServlet#findleaks(PrintWriter)
+ *
+ * @return message String
+ */
+ protected String findleaks() {
+
+ StringBuilder msg = new StringBuilder();
+
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter);
+
+ super.findleaks(printWriter);
+
+ if (stringWriter.getBuffer().length() > 0) {
+ msg.append(sm.getString("htmlManagerServlet.findleaksList"));
+ msg.append(stringWriter.toString());
+ } else {
+ msg.append(sm.getString("htmlManagerServlet.findleaksNone"));
+ }
+
+ return msg.toString();
+ }
+
/**
* @see javax.servlet.Servlet#getServletInfo()
@@ -1136,4 +1175,31 @@
"<br>\n" +
"\n";
+ private static final String DIAGNOSTICS_SECTION =
+ "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+ "<tr>\n" +
+ " <td colspan=\"2\" class=\"title\">{0}</td>\n" +
+ "</tr>\n" +
+ "<tr>\n" +
+ " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
+ "</tr>\n" +
+ "<tr>\n" +
+ " <td colspan=\"2\">\n" +
+ "<form method=\"post\" action=\"{2}\">\n" +
+ "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
+ "<tr>\n" +
+ " <td class=\"row-left\">\n" +
+ " <input type=\"submit\" value=\"{4}\">\n" +
+ " </td>\n" +
+ " <td class=\"row-left\">\n" +
+ " <small>{3}</small>\n" +
+ " </td>\n" +
+ "</tr>\n" +
+ "</table>\n" +
+ "</form>\n" +
+ "</td>\n" +
+ "</tr>\n" +
+ "</table>\n" +
+ "<br>";
+
}
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/LocalStrings.properties?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/LocalStrings.properties
(original)
+++
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/LocalStrings.properties
Wed Feb 24 00:07:06 2010
@@ -43,6 +43,12 @@
htmlManagerServlet.deployUploadNoFile=FAIL - File upload failed, no file
htmlManagerServlet.deployUploadWarExists=FAIL - War file \"{0}\" already
exists on server
htmlManagerServlet.deployWar=WAR or Directory URL:
+htmlManagerServlet.diagnosticsLeak=Check to see if a web application has
caused a memory leak on reload
+htmlManagerServlet.diagnosticsLeakButton=Find leaks
+htmlManagerServlet.diagnosticsLeakWarning=This diagnostic check will trigger a
full garbage collection. Use it with extreme caution on production systems.
+htmlManagerServlet.diagnosticsTitle=Diagnostics
+htmlManagerServlet.findleaksList=The following web applications appear to have
triggered a memory leak on reload (use a profiler to confirm):\n
+htmlManagerServlet.findleaksNone=No web applications appear to have triggered
a memory leak on reload.
htmlManagerServlet.list=List Applications
htmlManagerServlet.manager=Manager
htmlManagerServlet.messageLabel=Message:
@@ -63,6 +69,7 @@
managerServlet.deployFailed=FAIL - Failed to deploy application at context
path {0}
managerServlet.deployedButNotStarted=FAIL - Deployed application at context
path {0} but context failed to start
managerServlet.exception=FAIL - Encountered exception {0}
+managerServlet.findleaksFail=FAIL - Find leaks failed: Host not instance of
StandardHost
managerServlet.invalidPath=FAIL - Invalid context path {0} was specified
managerServlet.invalidWar=FAIL - Invalid application URL {0} was specified
managerServlet.listed=OK - Listed applications for virtual host {0}
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/ManagerServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/ManagerServlet.java?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/ManagerServlet.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/ManagerServlet.java
Wed Feb 24 00:07:06 2010
@@ -54,6 +54,7 @@
import org.apache.catalina.Session;
import org.apache.catalina.UserDatabase;
import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
@@ -379,6 +380,8 @@
stop(writer, path);
} else if (command.equals("/undeploy")) {
undeploy(writer, path);
+ } else if (command.equals("/findleaks")) {
+ findleaks(writer);
} else {
writer.println(sm.getString("managerServlet.unknownCommand",
command));
@@ -523,6 +526,28 @@
/**
+ * Find potential memory leaks caused by web application reload.
+ */
+ protected void findleaks(PrintWriter writer) {
+
+ if (!(host instanceof StandardHost)) {
+ writer.println(sm.getString("managerServlet.findleaksFail"));
+ return;
+ }
+
+ String[] results =
+ ((StandardHost) host).findReloadedContextMemoryLeaks();
+
+ for (String result : results) {
+ if ("".equals(result)) {
+ result = "/";
+ }
+ writer.println(result);
+ }
+ }
+
+
+ /**
* Store server configuration.
*
* @param path Optional context path to save
Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Wed Feb 24 00:07:06 2010
@@ -108,6 +108,11 @@
Modify ThreadLocal memory leak detection to not report false positives
and to simplify implementation. (markt/kkolinko)
</update>
+ <add>
+ Basic memory leak detection was added to the standard Host
+ implementation and exposed via JMX to detect memory leaks on web
+ application reload. (markt/kkolinko)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">
@@ -150,6 +155,14 @@
</fix>
</changelog>
</subsection>
+ <subsection name="Webapps">
+ <changelog>
+ <add>
+ Make the new web application reload memory leak detection available
+ through the Manager application. (markt/kkolinko)
+ </add>
+ </changelog>
+ </subsection>
<subsection name="Other">
<changelog>
<fix>
Modified: tomcat/tc6.0.x/trunk/webapps/docs/html-manager-howto.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/html-manager-howto.xml?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/html-manager-howto.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/html-manager-howto.xml Wed Feb 24
00:07:06 2010
@@ -36,7 +36,7 @@
Tomcat. This document is for the HTML web interface to the web application
<a href="manager-howto.html">manager</a>.</p>
-<p>The interface is divided into five sections:
+<p>The interface is divided into six sections:
<ul>
<li><strong>Message</strong> - Displays success and failure messages.</li>
<li><strong>Manager</strong> - General manager operations like list and
@@ -44,6 +44,7 @@
<li><strong>Applications</strong> - List of web applications and
commands.</li>
<li><strong>Deploy</strong> - Deploying web applications.</li>
+ <li><strong>Diagnostics</strong> - Identifying potential problems.</li>
<li><strong>Server Information</strong> - Information about the Tomcat
server.</li>
</ul>
@@ -546,6 +547,19 @@
</subsection>
</section>
+<section name="Diagnostics">
+
+<p><strong>The find leaks diagnostic triggers a full garbage collection. It
+should be used with extreme caution on production systems.</strong></p>
+
+<p>The find leaks diagnostic attempts to identify web applications that have
+caused memory leaks when they were reloaded. Results should always be confirmed
+with a profiler. The diagnostic uses additional functionality provided by the
+StandardHost implementation. It will not work if a custom host is used that
+does not extend StandardHost.</p>
+
+</section>
+
<section name="Server Information">
<p>This section displays information about Tomcat, the operating system of
Modified: tomcat/tc6.0.x/trunk/webapps/docs/manager-howto.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/manager-howto.xml?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/manager-howto.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/manager-howto.xml Wed Feb 24 00:07:06 2010
@@ -51,6 +51,8 @@
<a href="#Stop an Existing Application">Stop an Existing Application</a><br />
<a href="#Undeploy an Existing Application">
Undeploy an Existing Application</a><br />
+<a href="#Server Status">Server Status</a><br />
+<a href="#Finding memory leaks">Finding memory leaks</a><br />
</blockquote>
<a href="#Executing Manager Commands With Ant">
Executing Manager Commands With Ant</a><br />
@@ -897,6 +899,35 @@
</subsection>
+<subsection name="Finding memory leaks">
+
+<source>
+http://localhost:8080/manager/findleaks
+</source>
+
+<p><strong>The find leaks diagnostic triggers a full garbage collection. It
+should be used with extreme caution on production systems.</strong></p>
+
+<p>The find leaks diagnostic attempts to identify web applications that have
+caused memory leaks when they were reloaded. Results should always be confirmed
+with a profiler. The diagnostic uses additional functionality provided by the
+StandardHost implementation. It will not work if a custom host is used that
+does not extend StandardHost.</p>
+
+<p>If this command succeeds, you will see a response like this:</p>
+<source>
+/leaking-webapp
+</source>
+
+<p>Each context path for a web application that is believed to have triggered a
+memory leak when it was reloaded will be listed on a new line. If an
application
+has been reloaded several times, it may be listed several times.</p>
+
+<p>If the command does not succeed, the response will start with
+<code>FAIL</code> and include an error message.</p>
+
+</subsection>
+
<subsection name="Server Status">
<p>From this link , you can view information about the server.</p>
Modified: tomcat/tc6.0.x/trunk/webapps/manager/WEB-INF/web.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/manager/WEB-INF/web.xml?rev=915603&r1=915602&r2=915603&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/manager/WEB-INF/web.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/manager/WEB-INF/web.xml Wed Feb 24 00:07:06
2010
@@ -121,6 +121,10 @@
<url-pattern>/resources</url-pattern>
</servlet-mapping>
<servlet-mapping>
+ <servlet-name>Manager</servlet-name>
+ <url-pattern>/findleaks</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
<servlet-name>Status</servlet-name>
<url-pattern>/status/*</url-pattern>
</servlet-mapping>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]