Cleanly starting apps on Java 9 and earlier
Hi, Apache Tomcat needs to add the following options when running on Java 9: --add-modules=java.se.ee --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED The first is because it depends on javax.xml.ws.WebServiceRef and javax.xml.ws.WebServiceRefs. We could work around this by shipping our own implementations but that sort of duplication should not be necessary. The second and third are required by Tomcat's memory leak detection and prevention code. In an ideal world, web applications wouldn't have memory leaks. Unfortunately, the world isn't ideal and the memory leak detection and prevention code has proven immensely valuable over the years. The problem we have is that Tomcat needs to run on Java 9 though 6. If the above options aren't provided, Java 6 through 8 are fine but on Java 9 at best the users see a bunch of errors and at worst Tomcat won't start. If the above options are included, Java 9 is fine but then Tomcat fails to start on Java 6 though 8. What is the recommended approach for applications that need to use one or more of the options above and need to start cleanly on multiple Java versions including 9 and earlier using a single, common start-up script? To date, Tomcat has always been Java version agnostic as long as at least the minimum Java version as specified by the Java EE spec has been used. We really don't want to have to change that. Suggestions welcome. Mark
Re: Cleanly starting apps on Java 9 and earlier
On 01/07/17 10:53, Alan Bateman wrote: > On 01/07/2017 10:18, Mark Thomas wrote: >> Hi, >> >> Apache Tomcat needs to add the following options when running on Java 9: >> >> --add-modules=java.se.ee >> --add-opens=java.base/java.lang=ALL-UNNAMED >> --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED >> >> The first is because it depends on javax.xml.ws.WebServiceRef and >> javax.xml.ws.WebServiceRefs. >> We could work around this by shipping our own implementations but that >> sort of duplication should not be necessary. > The java.xml.ws module is deprecated for removal (along with the other > modules shared with Java EE) so expect these modules to not be included > in the JDK some day (exactly when is TBD as it depends on when Java SE > drops them). > > In the short term then `--add-modules java.se.ee` will resolve the EE > modules included in the JDK but it may bring complications, it all > depends on whether you have the EE java.transaction module or JAR files > with annotations in the javax.annotation package in your environment. An > important page for the JDK 9 docs is a page with instructions and > deployments options for those using these APIs. Alan, Thanks for the info. Tomcat only recently dropped its own implementation of those classes so the simplest thing to do is reinstate them. >> The second and third are required by Tomcat's memory leak detection and >> prevention code. In an ideal world, web applications wouldn't have >> memory leaks. Unfortunately, the world isn't ideal and the memory leak >> detection and prevention code has proven immensely valuable over the >> years. > Both of these packages are open since jdk-9+175 so the hacks to null > fields will continue to work. Yep. Partly I want to avoid the warnings entirely - for some users start-up warnings are errors that MUST be resolved. > That said, I thought the issue with TCCL in sun.rmi.transport.GC was > fixed via JDK-8157570. Have you tested that? Yes that bug is fixed. The RMI leaks in this case are application bugs, not JRE bugs. They are typically caused by applications registering stuff for RMI and then failing to de-register it. Tomcat needs to poke around in the internals to find out if such a memory leak is present. >> The problem we have is that Tomcat needs to run on Java 9 though 6. If >> the above options aren't provided, Java 6 through 8 are fine but on Java >> 9 at best the users see a bunch of errors and at worst Tomcat won't >> start. If the above options are included, Java 9 is fine but then Tomcat >> fails to start on Java 6 though 8. >> > The launch script could examine the JAVA_VERSION property in the > `release` file. Another approach is to set the JDK_JAVA_OPTIONS > environment variable as that is new 9 and so will be ignored by older > releases. There is also -XX:+IgnoreUnrecognizedVMOptions to ignore > unrecognized options. Excellent. JDK_JAVA_OPTIONS is exactly what I need. Many thanks for the response. Kind regards, Mark
Re: Cleanly starting apps on Java 9 and earlier
On 01/07/17 14:57, Stephen Felts wrote: > IMO: > > 1. You should avoid `--add-modules java.se.ee' unless you need all of those > modules. You should bring in only those modules that you need. The choices > are java.activation, java.corba, java.transaction, java.xml.bind, > java.xml.ws, > java.xml.ws.annotation. So use --add-modules java.xml.ws. Thanks for the tip. > 2. You can't use -XX:+IgnoreUnrecognizedVMOptions as a general solution > because that isn't available in JDK6 JRockit for example. Good to know. I was leaning towards JDK_JAVA_OPTIONS anyway. This point confirms that choice. > 3. Setting JDK_JAVA_OPTIONS is good because only JDK9 recognizes it and it is > inherited by all nested invocations (unless there is an exec that excludes > the environment). You might want to use > export JDK_JAVA_OPTIONS="-XX:+IgnoreUnrecognizedVMOptions --add-modules > java.xml.ws" > > 4. --add-opens is not needed starting in b175 so require that as a base. It > will still be noisy (a 3-line WARNING will be printed to the standard error). Tomcat won't officially support Java 9 until there is a GA release. Anything before then is on the basis that is should work, but it might not. Thanks again for the additional info. Mark > > > -Original Message- > From: Alan Bateman > Sent: Saturday, July 1, 2017 5:53 AM > To: Mark Thomas; jigsaw-dev@openjdk.java.net > Subject: Re: Cleanly starting apps on Java 9 and earlier > > On 01/07/2017 10:18, Mark Thomas wrote: >> Hi, >> >> Apache Tomcat needs to add the following options when running on Java 9: >> >> --add-modules=java.se.ee >> --add-opens=java.base/java.lang=ALL-UNNAMED >> --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED >> >> The first is because it depends on javax.xml.ws.WebServiceRef and >> javax.xml.ws.WebServiceRefs. >> We could work around this by shipping our own implementations but that >> sort of duplication should not be necessary. > The java.xml.ws module is deprecated for removal (along with the other > modules shared with Java EE) so expect these modules to not be included in > the JDK some day (exactly when is TBD as it depends on when Java SE drops > them). > > In the short term then `--add-modules java.se.ee` will resolve the EE modules > included in the JDK but it may bring complications, it all depends on whether > you have the EE java.transaction module or JAR files with annotations in the > javax.annotation package in your environment. An important page for the JDK 9 > docs is a page with instructions and deployments options for those using > these APIs. > > >> >> The second and third are required by Tomcat's memory leak detection >> and prevention code. In an ideal world, web applications wouldn't have >> memory leaks. Unfortunately, the world isn't ideal and the memory leak >> detection and prevention code has proven immensely valuable over the years. > Both of these packages are open since jdk-9+175 so the hacks to null fields > will continue to work. > > That said, I thought the issue with TCCL in sun.rmi.transport.GC was fixed > via JDK-8157570. Have you tested that? > > >> The problem we have is that Tomcat needs to run on Java 9 though 6. If >> the above options aren't provided, Java 6 through 8 are fine but on Java >> 9 at best the users see a bunch of errors and at worst Tomcat won't >> start. If the above options are included, Java 9 is fine but then Tomcat >> fails to start on Java 6 though 8. >> > The launch script could examine the JAVA_VERSION property in the > `release` file. Another approach is to set the JDK_JAVA_OPTIONS > environment variable as that is new 9 and so will be ignored by older > releases. There is also -XX:+IgnoreUnrecognizedVMOptions to ignore > unrecognized options. > > -Alan >
Project Jigsaw, Apache Tomcat and RMI related memory leaks
Hi, The Apache Tomcat community was asked by Rory O'Donnell for feedback on JDK 9 + Project Jigsaw. Having provided that feedback we were directed here so I have reproduced that feedback below. I've started testing Tomcat trunk with JDK 9 + Project Jigsaw and it looks like we are going to hit a bunch of problems related to Tomcat's memory leak protection. The short version is there are lots of JDK calls that can result in a reference being retained to the current class loader. If that class loader is the web application class loader it often ends up being pinned in memory. This triggers a memory leak when the web application is reloaded since the web application class loader is not eligible for GC. Tomcat generally uses reflection to find these problems. It then does one of two things: - If the JRE provides an API the application developer should have used to clean up the reference, Tomcat does this for them and then logs a very loud error message telling the developer they need to fix their app. - If there is nothing the developer could have done to avoid the problem, Tomcat cleans it up. Usually this is via reflection again. Reporting this second class of issues as JRE bugs has been on my TODO list for a long time. It looks like Java 9 is going to bump this to the top of the list. The first problem we have hit is related to RMI. The memory leak is triggered by a call to: java.rmi.registry.Registry.bind() or java.rmi.registry.Registry.rebind() The problem occurs when an object of a class loaded by the web application class loader is bound to the RMI registry. There is no standard API (that I have found) that completely removes all references. In particular java.rmi.registry.Registry.unbind() doesn't help. The code Tomcat uses to clean this up is at [1]. Essentially, we need to remove any reference to the web application's class loader from the RMI caches. With JDK 9 this fails with: java.lang.reflect.InaccessibleObjectException: Unable to make member of class sun.rmi.transport.Target accessible: module java.rmi does not export sun.rmi.transport to unnamed module ... I took a look at the JDK 9 API but I could not find a way to bypass this. Possible solutions include: 1. Some way that allows us to continue to use reflection as per the current code. 2. A new method somewhere in the RMI API that clears all references associated with a given class loader from the cache. 3. Modify Registry.unbind() so it removes all references. 4. Something else... I do have a concern with 3 on its own that, while that would allow applications to clear their own references, it would mean Tomcat would have no way to check for the problem. Ideally, I'd like to see the API extended so a) applications are able to clean up after themselves and b) Tomcat can check for leaked references and generate error messages for the ones found. Any and all suggestions gratefully received. Thanks, Mark [1] http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoaderBase.java?view=annotate#l2214
Re: Project Jigsaw, Apache Tomcat and RMI related memory leaks
On 18/04/2016 12:14, Alan Bateman wrote: > On 18/04/2016 10:18, Mark Thomas wrote: >> Hi, >> >> The Apache Tomcat community was asked by Rory O'Donnell for feedback on >> JDK 9 + Project Jigsaw. Having provided that feedback we were directed >> here so I have reproduced that feedback below. >> >> >> I've started testing Tomcat trunk with JDK 9 + Project Jigsaw and it >> looks like we are going to hit a bunch of problems related to Tomcat's >> memory leak protection. >> >> The short version is there are lots of JDK calls that can result in a >> reference being retained to the current class loader. If that class >> loader is the web application class loader it often ends up being pinned >> in memory. This triggers a memory leak when the web application is >> reloaded since the web application class loader is not eligible for GC. >> >> Tomcat generally uses reflection to find these problems. It then does >> one of two things: >> - If the JRE provides an API the application developer should have used >> to clean up the reference, Tomcat does this for them and then logs a >> very loud error message telling the developer they need to fix their app. >> - If there is nothing the developer could have done to avoid the >> problem, Tomcat cleans it up. Usually this is via reflection again. >> >> Reporting this second class of issues as JRE bugs has been on my TODO >> list for a long time. It looks like Java 9 is going to bump this to the >> top of the list. > I remember you brought this up on core-libs-dev [1] and the suggestion > at the time was to create bugs for any of the issues that are still > relevant. So yes, bumping the priority on that would be good. > > On the RMI issue then it would be good to start a thread specifically on > this topic on core-libs-dev. OK. I'll restart this thread there. I'm also reviewing the various other leaks and I'll start new threads as each one is confirmed. Mark