Author: markt Date: Tue Mar 13 23:24:01 2018 New Revision: 1826688 URL: http://svn.apache.org/viewvc?rev=1826688&view=rev Log: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=51195 Avoid a false positive report of a web application memory leak by clearing ObjectStreamClass$Caches of classes loaded by the web application when the web application is stopped.
Modified: tomcat/trunk/bin/catalina.bat tomcat/trunk/bin/catalina.sh tomcat/trunk/bin/service.bat tomcat/trunk/java/org/apache/catalina/core/StandardContext.java tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoaderBase.java tomcat/trunk/res/tomcat.nsi tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/context.xml tomcat/trunk/webapps/docs/setup.xml Modified: tomcat/trunk/bin/catalina.bat URL: http://svn.apache.org/viewvc/tomcat/trunk/bin/catalina.bat?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/bin/catalina.bat (original) +++ tomcat/trunk/bin/catalina.bat Tue Mar 13 23:24:01 2018 @@ -224,6 +224,7 @@ set LOGGING_MANAGER=-Djava.util.logging. rem Configure JAVA 9 specific start-up parameters set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.base/java.lang=ALL-UNNAMED" +set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.base/java.io=ALL-UNNAMED" set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED" rem Java 9 no longer supports the java.endorsed.dirs Modified: tomcat/trunk/bin/catalina.sh URL: http://svn.apache.org/viewvc/tomcat/trunk/bin/catalina.sh?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/bin/catalina.sh (original) +++ tomcat/trunk/bin/catalina.sh Tue Mar 13 23:24:01 2018 @@ -302,6 +302,7 @@ fi # Add the JAVA 9 specific start-up parameters required by Tomcat JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-opens=java.base/java.lang=ALL-UNNAMED" +JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-opens=java.base/java.io=ALL-UNNAMED" JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED" export JDK_JAVA_OPTIONS Modified: tomcat/trunk/bin/service.bat URL: http://svn.apache.org/viewvc/tomcat/trunk/bin/service.bat?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/bin/service.bat (original) +++ tomcat/trunk/bin/service.bat Tue Mar 13 23:24:01 2018 @@ -184,7 +184,7 @@ if "%JvmMx%" == "" set JvmMx=256 --StartParams start ^ --StopParams stop ^ --JvmOptions "-Dcatalina.home=%CATALINA_HOME%;-Dcatalina.base=%CATALINA_BASE%;-D%ENDORSED_PROP%=%CATALINA_HOME%\endorsed;-Djava.io.tmpdir=%CATALINA_BASE%\temp;-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager;-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties;%JvmArgs%" ^ - --JvmOptions9 "--add-opens=java.base/java.lang=ALL-UNNAMED#--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED" ^ + --JvmOptions9 "--add-opens=java.base/java.lang=ALL-UNNAMED#--add-opens=java.base/java.io=ALL-UNNAMED#--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED" ^ --Startup "%SERVICE_STARTUP_MODE%" ^ --JvmMs "%JvmMs%" ^ --JvmMx "%JvmMx%" Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Tue Mar 13 23:24:01 2018 @@ -737,6 +737,12 @@ public class StandardContext extends Con private boolean renewThreadsWhenStoppingContext = true; /** + * Should Tomcat attempt to clear references to classes loaded by the web + * application class loader from the ObjectStreamClass caches? + */ + private boolean clearReferencesObjectStreamClassCaches = true; + + /** * Should the effective web.xml be logged when the context starts? */ private boolean logEffectiveWebXml = false; @@ -2652,6 +2658,23 @@ public class StandardContext extends Con this.renewThreadsWhenStoppingContext); } + + public boolean getClearReferencesObjectStreamClassCaches() { + return clearReferencesObjectStreamClassCaches; + } + + + public void setClearReferencesObjectStreamClassCaches( + boolean clearReferencesObjectStreamClassCaches) { + boolean oldClearReferencesObjectStreamClassCaches = + this.clearReferencesObjectStreamClassCaches; + this.clearReferencesObjectStreamClassCaches = clearReferencesObjectStreamClassCaches; + support.firePropertyChange("clearReferencesObjectStreamClassCaches", + oldClearReferencesObjectStreamClassCaches, + this.clearReferencesObjectStreamClassCaches); + } + + public Boolean getFailCtxIfServletStartFails() { return failCtxIfServletStartFails; } @@ -4901,6 +4924,8 @@ public class StandardContext extends Con getClearReferencesStopTimerThreads()); setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread", getClearReferencesHttpClientKeepAliveThread()); + setClassLoaderProperty("clearReferencesObjectStreamClassCaches", + getClearReferencesObjectStreamClassCaches()); // By calling unbindThread and bindThread in a row, we setup the // current Thread CCL to be the webapp classloader Modified: tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/loader/LocalStrings.properties Tue Mar 13 23:24:01 2018 @@ -22,6 +22,7 @@ webappClassLoader.jdbcRemoveFailed=JDBC webappClassLoader.stopped=Illegal access: this web application instance has been stopped already. Could not load [{0}]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. webappClassLoader.readError=Resource read error: Could not load [{0}]. webappClassLoader.clearJdbc=The web application [{0}] registered the JDBC driver [{1}] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. +webappClassLoader.clearObjectStreamClassCachesFail=Failed to clear soft references from ObjectStreamClass$Caches for web application [{0}] webappClassLoader.clearReferencesResourceBundlesCount=Removed [{0}] ResourceBundle references from the cache for web application [{1}] webappClassLoader.clearReferencesResourceBundlesFail=Failed to clear ResourceBundle references for web application [{0}] webappClassLoader.clearRmi=Found RMI Target with stub class class [{0}] and value [{1}]. This RMI Target has been forcibly removed to prevent a memory leak. Modified: tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoaderBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoaderBase.java?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoaderBase.java (original) +++ tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoaderBase.java Tue Mar 13 23:24:01 2018 @@ -362,6 +362,12 @@ public abstract class WebappClassLoaderB private boolean clearReferencesHttpClientKeepAliveThread = true; /** + * Should Tomcat attempt to clear references to classes loaded by this class + * loader from the ObjectStreamClass caches? + */ + private boolean clearReferencesObjectStreamClassCaches = true; + + /** * Holds the class file transformers decorating this class loader. The * CopyOnWriteArrayList is thread safe. It is expensive on writes, but * those should be rare. It is very fast on reads, since synchronization @@ -596,6 +602,17 @@ public abstract class WebappClassLoaderB } + public boolean getClearReferencesObjectStreamClassCaches() { + return clearReferencesObjectStreamClassCaches; + } + + + public void setClearReferencesObjectStreamClassCaches( + boolean clearReferencesObjectStreamClassCaches) { + this.clearReferencesObjectStreamClassCaches = clearReferencesObjectStreamClassCaches; + } + + // ------------------------------------------------------- Reloader Methods /** @@ -1513,6 +1530,11 @@ public abstract class WebappClassLoaderB // Stop any threads the web application started clearReferencesThreads(); + // Clear any references retained in the serialization caches + if (clearReferencesObjectStreamClassCaches) { + clearReferencesObjectStreamClassCaches(); + } + // Check for leaks triggered by ThreadLocals loaded by this class loader checkThreadLocalsForLeaks(); @@ -2132,6 +2154,36 @@ public abstract class WebappClassLoaderB } } } + + + private void clearReferencesObjectStreamClassCaches() { + try { + Class<?> clazz = Class.forName("java.io.ObjectStreamClass$Caches"); + clearCache(clazz, "localDescs"); + clearCache(clazz, "reflectors"); + } catch (ReflectiveOperationException | SecurityException | ClassCastException e) { + log.warn(sm.getString( + "webappClassLoader.clearObjectStreamClassCachesFail", getContextName()), e); + } + } + + + private void clearCache(Class<?> target, String mapName) + throws ReflectiveOperationException, SecurityException, ClassCastException { + Field f = target.getDeclaredField(mapName); + f.setAccessible(true); + Map<?,?> map = (Map<?,?>) f.get(null); + Iterator<?> keys = map.keySet().iterator(); + while (keys.hasNext()) { + Object key = keys.next(); + if (key instanceof Reference) { + Object clazz = ((Reference<?>) key).get(); + if (loadedByThisOrChild(clazz)) { + keys.remove(); + } + } + } + } /** Modified: tomcat/trunk/res/tomcat.nsi URL: http://svn.apache.org/viewvc/tomcat/trunk/res/tomcat.nsi?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/res/tomcat.nsi (original) +++ tomcat/trunk/res/tomcat.nsi Tue Mar 13 23:24:01 2018 @@ -322,7 +322,7 @@ Section -post FileWrite $ServiceInstallLog "$\r$\n" FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions "-Dcatalina.home=$INSTDIR#-Dcatalina.base=$INSTDIR#-Djava.io.tmpdir=$INSTDIR\temp#-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager#-Djava.util.logging.config.file=$INSTDIR\conf\logging.properties"' FileWrite $ServiceInstallLog "$\r$\n" - FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions9 "--add-opens=java.base/java.lang=ALL-UNNAMED#--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"' + FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions9 "--add-opens=java.base/java.lang=ALL-UNNAMED#--add-opens=java.base/java.io=ALL-UNNAMED#--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"' FileWrite $ServiceInstallLog "$\r$\n" FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --StdOutput auto --StdError auto --JvmMs 128 --JvmMx 256' FileWrite $ServiceInstallLog "$\r$\n" @@ -332,7 +332,7 @@ Section -post DetailPrint "Configuring $TomcatServiceName service" nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --Classpath "$INSTDIR\bin\bootstrap.jar;$INSTDIR\bin\tomcat-juli.jar" --StartClass org.apache.catalina.startup.Bootstrap --StopClass org.apache.catalina.startup.Bootstrap --StartParams start --StopParams stop --StartMode jvm --StopMode jvm' nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions "-Dcatalina.home=$INSTDIR#-Dcatalina.base=$INSTDIR#-Djava.io.tmpdir=$INSTDIR\temp#-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager#-Djava.util.logging.config.file=$INSTDIR\conf\logging.properties"' - nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions9 "--add-opens=java.base/java.lang=ALL-UNNAMED#--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"' + nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions9 "--add-opens=java.base/java.lang=ALL-UNNAMED#--add-opens=java.base/java.io=ALL-UNNAMED#--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"' nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --StdOutput auto --StdError auto --JvmMs 128 --JvmMx 256' ${If} $TomcatShortcutAllUsers == "1" Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Mar 13 23:24:01 2018 @@ -48,6 +48,12 @@ <subsection name="Catalina"> <changelog> <fix> + <bug>51195</bug>: Avoid a false positive report of a web application + memory leak by clearing <code>ObjectStreamClass$Caches</code> of classes + loaded by the web application when the web application is stopped. + (markt) + </fix> + <fix> Ensure the MBean names for the <code>SSLHostConfig</code> and <code>SSLHostConfigCertificate</code> are correctly formed when the <code>Connector</code> is bound to a specific IP address. (markt) Modified: tomcat/trunk/webapps/docs/config/context.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/context.xml?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/context.xml (original) +++ tomcat/trunk/webapps/docs/config/context.xml Tue Mar 13 23:24:01 2018 @@ -711,6 +711,18 @@ not specified, the default value of <code>true</code> will be used.</p> </attribute> + <attribute name="clearReferencesObjectStreamClassCaches" required="false"> + <p>If <code>true</code>, when the web application is stopped Tomcat + looks for <code>SoftReference</code>s to classes loaded by the web + application in the <code>ObjectStreamClass</code> class used for + serialization and clears any <code>SoftReference</code>s it finds. This + feature uses reflection to identify the <code>SoftReference</code>s and + therefore requires that the command line option + <code>-XaddExports:java.base/java.io=ALL-UNNAMED</code> is set + when running on Java 9 and above. If not specified, the default value of + <code>true</code> will be used.</p> + </attribute> + <attribute name="clearReferencesRmiTargets" required="false"> <p>If <code>true</code>, Tomcat looks for memory leaks associated with RMI Targets and clears any it finds. This feature uses reflection to Modified: tomcat/trunk/webapps/docs/setup.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/setup.xml?rev=1826688&r1=1826687&r2=1826688&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/setup.xml (original) +++ tomcat/trunk/webapps/docs/setup.xml Tue Mar 13 23:24:01 2018 @@ -157,6 +157,7 @@ cd $CATALINA_HOME following when starting jsvc to avoid warnings on shutdown.</p> <source>... --add-opens=java.base/java.lang=ALL-UNNAMED \ +--add-opens=java.base/java.io=ALL-UNNAMED \ --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED \ ... </source> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org