Author: remy.maucherat(a)jboss.com
Date: 2009-11-25 19:25:58 -0500 (Wed, 25 Nov 2009)
New Revision: 1297
Modified:
trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
Log:
- Sync, for reference.
Modified: trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
===================================================================
--- trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java 2009-11-25
17:36:34 UTC (rev 1296)
+++ trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java 2009-11-26
00:25:58 UTC (rev 1297)
@@ -17,21 +17,75 @@
package org.apache.catalina.core;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
import javax.imageio.ImageIO;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
+import org.apache.tomcat.util.res.StringManager;
/**
- * Provide a workaround for known places where the Java Runtime environment uses
+ * Provide a workaround for known places where the Java Runtime environment can
+ * cause a memory leak or lock files.
+ * <p>
+ * Memory leaks occur when JRE code uses
* the context class loader to load a singleton as this will cause a memory leak
* if a web application class loader happens to be the context class loader at
* the time. The work-around is to initialise these singletons when Tomcat's
* common class loader is the context class loader.
+ * <p>
+ * Locked files usually occur when a resource inside a JAR is accessed without
+ * first disabling Jar URL connection caching. The workaround is to disable this
+ * caching by default.
*/
public class JreMemoryLeakPreventionListener implements LifecycleListener {
+ private static org.jboss.logging.Logger log =
+ org.jboss.logging.Logger.getLogger(JreMemoryLeakPreventionListener.class);
+ protected static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+ /**
+ * Protect against the memory leak caused when the first call to
+ * <code>sun.awt.AppContext.getAppContext()</code> is triggered by a web
+ * application. Defaults to <code>true</code>.
+ */
+ protected boolean appContextProtection = true;
+ public boolean isAppContextProtection() { return appContextProtection; }
+ public void setAppContextProtection(boolean appContextProtection) {
+ this.appContextProtection = appContextProtection;
+ }
+
+ /**
+ * Protect against resources being read for JAR files and, as a side-effect,
+ * the JAR file becoming locked. Note this disables caching for all
+ * {@link URLConnection}s, regardless of type. Defaults to
+ * <code>true</code>.
+ */
+ protected boolean urlCacheProtection = true;
+ public boolean isUrlCacheProtection() { return urlCacheProtection; }
+ public void setUrlCacheProtection(boolean urlCacheProtection) {
+ this.urlCacheProtection = urlCacheProtection;
+ }
+
+ /**
+ * XML parsing can pin a web application class loader in memory. This is
+ * particularly nasty as profilers (at least YourKit and Eclispe MAT) don't
+ * idenitfy any GC roots related to this.
+ */
+ protected boolean xmlParsingProtection = true;
+ public boolean isXmlParsingProtection() { return xmlParsingProtection; }
+ public void setXmlParsingProtection(boolean xmlParsingProtection) {
+ this.xmlParsingProtection = xmlParsingProtection;
+ }
+
@Override
public void lifecycleEvent(LifecycleEvent event) {
// Initialise these classes when Tomcat starts
@@ -42,7 +96,6 @@
*
* Those libraries / components known to trigger memory leaks due to
* eventual calls to getAppContext() are:
- *
* - Google Web Toolkit via its use of javax.imageio
* - Tomcat via its use of java.beans.Introspector.flushCaches() in
* 1.6.0_15 onwards
@@ -52,8 +105,53 @@
// Trigger a call to sun.awt.AppContext.getAppContext(). This will
// pin the common class loader in memory but that shouldn't be an
// issue.
- ImageIO.getCacheDirectory();
+ if (appContextProtection) {
+ ImageIO.getCacheDirectory();
+ }
+ /*
+ * Several components end up opening JarURLConnections without first
+ * disabling caching. This effectively locks the file. Whilst more
+ * noticeable and harder to ignore on Windows, it affects all
+ * operating systems.
+ *
+ * Those libraries/components known to trigger this issue include:
+ * - log4j versions 1.2.15 and earlier
+ * - javax.xml.bind.JAXBContext.newInstance()
+ */
+
+ // Set the default URL caching policy to not to cache
+ if (urlCacheProtection) {
+ try {
+ // Doesn't matter that this JAR doesn't exist - just as long
as
+ // the URL is well-formed
+ URL url = new URL("jar:file://dummy.jar!/");
+ URLConnection uConn = url.openConnection();
+ uConn.setDefaultUseCaches(false);
+ } catch (MalformedURLException e) {
+ log.error(sm.getString(
+ "jreLeakListener.jarUrlConnCacheFail"), e);
+ } catch (IOException e) {
+ log.error(sm.getString(
+ "jreLeakListener.jarUrlConnCacheFail"), e);
+ }
+ }
+
+ /*
+ * Haven't got to the root of what is going on with this leak but if
+ * a web app is the first to make the calls below the web
+ * application class loader will be pinned in memory.
+ */
+ if (xmlParsingProtection) {
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ try {
+ factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ log.error(sm.getString(
+ "jreLeakListener.xmlParseFail"), e);
+ }
+ }
}
}
Show replies by date