JDK 9: Pitfalls for the unwary

Simon Ritter
© Shutterstock / Kelly Marken

JDK 9 is almost here and there are so many new features to discover. In this article, Simon Ritter, speaker at the upcoming JAX London conference, explains some of the issues that you need to be aware of when migrating your apps to JDK 9.

JDK 9 is in the final phases of development, heading towards release on September 21st. The public review consideration ballot for the Java Platform Module System was passed [almost] unanimously, and so everything is now back on track.

You can download the Azul Zulu builds of (Early Access) OpenJDK 9 here.

Recently I’ve been doing a presentation entitled, “55 New Features in JDK 9”. In this, I’ve tried to focus almost entirely on things that are not JPMS. What this has revealed is that there are a few areas of change in JDK 9 that could catch people out regarding compatibility with earlier versions. I’ve also been noticing a number of questions related to these things appearing on Stackoverflow.

This blog is a summary of all the things I’ve been able to find that might require you to change something when migrating your applications to JDK 9. What I’m not going to do here is talk about JPMS, encapsulation of non-public classes, effects on reflective access and so on. That’s a whole different set of issues. This collection is just about the other things that you need to be aware of.

SEE MORE: Java 9 modules – JPMS basics

1. Identifiers. JEP 213, Milling Project Coin brings a small change that hopefully won’t affect many people. In earlier versions of Java, it was possible (though not advisory) to use a single underscore as an identifier (i.e. a variable name). In JDK 9, a single underscore is now a keyword. This may sound bizarre, but is the easiest way of preventing its use as an identifier. The plan is that, possibly in JDK 10, it will be possible to use an underscore as an identifier in Lambda expressions only. This will allow a little cleaner syntax for the situation where your Lambda has a single parameter, which is not used in the body of the Lambda (e.g. _ -> foo())

2. The layout of the JDK has changed (JEP 220): If you rely on the location of JDK specific files relative to $JAVA_HOME, you may need to make some changes. There’s a number of distinct differences here:

  • There is no more separate jre sub-directory, with a separate copy of the bin, lib, and so on directories. The JDK directory structure is now flat with a single bin directory (and therefore only one copy of the java executable), the lib directory is for native libraries and the jmods directory for the JDK modules. There is also a new conf directory that contains all files that, as administrator, you might need to change to modify the JDK configuration. This has things like networking and logging properties.
  • The switch to modules means that there are no more rt.jar or tools.jar files. If you access these directly, you will need to change your code.
  • The hprof agent has been removed from JDK 9 (JEP 240) and as a consequence the lib/ (or bin/hprof.dll on Windows) files have been deleted as well.

3. The JDK version string (JEP 223): The old way of defining the version of the JDK was rather confusing. We had JDK 8u131, for example, but if you run java -version you’ll get back java version "1.8.0_131". To simplify this for both humans and applications, the format is now JDK $MAJOR.$MINOR.$SECURITY.$PATCH, so java -version on JDK9 returns java version "9" (this will change once the release is final and we start getting updates). The important thing here is that, if you use the version string of the JVM in your code and rely on the current format you’ll have to make changes to run correctly on JDK 9.

SEE MORE: “Java 9 is much bigger than Jigsaw”

4. Thread.stop(Throwable) now throws an UnsupportedOperationException, which it did not do before. This method has been deprecated since deprecation first started due to its inherent lack of thread safety. The other version of Thread.stop(), which takes no arguments will still work without throwing an exception (but is still deprecated and you are strongly advised not to use this)

5. The Java Network Launch Protocol (JNLP) has been updated to allow strict parsing of the configuration files. The format used now conforms to the XML specification by requiring “&” version-range combiner be expressed as “&”. Parsing of the configuration is now strict, meaning some files that would have worked with older versions of Java will now produce errors. More details can be found on the JSR 52 maintenance page.

6. Related to JPMS the extension mechanism (for optional packages) and the endorsed standards override mechanism have both been removed and replaced with JPMS equivalents. As a consequence, the $JAVA_HOME/lib/ext and $JAVA_HOME/lib/endorsed directories have been deleted. If you recreate these and try putting things in them in the hope that this will still work, it won’t. The JVM will fail to start of it finds these directories, and you will get the following error message:

/lib/ext exists, extensions mechanism no longer supported; Use -classpath instead.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

7. Six previously deprecated public methods have been deleted. This is a pretty big deal, as these are the first APIs to be eliminated in the history of Java. The methods that have been removed are the addPropertyChangeListener() and removePropertyChangeListener() from the java.util.jar.Pack200java.util.jar.Unpack200 and java.util.logging.LogManager classes.

SEE MORE: Top 9 improvements and features in Java 9

8. The class, which was part of the Java Authentication and Authorization Service (JAAS), has been removed. This was deprecated in JDK 8.

9. JRE version selection is no longer available. There were two ways of doing this in the past. The first was from the command line using the -version: option. If you use this, the JVM will abort without starting. The second way was from the manifest of a jar file. In this case, JDK 9 will ignore the directive but start up normally. It was felt that forcing people to change the manifest was too onerous compared to changing the command line. Please note that the -version option (without a following colon and version-id) still works quite happily to report which version of the Java runtime you have.

10. Deprecated GC options have been removed (JEP 214). There were a number of specific GC options and combinations of options that were deprecated in JDK 8 (JEP 173). These will not now be recognised and will cause the JVM to abort when it starts. The options to be aware of are shown below
-XX:-UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC -XX:-UseParNewGC

In JDK 9, the incremental mode of concurrent-mark-sweep (iCMS) has been removed, and the current plan is to remove CMS completely in JDK 10

Command line options

This seems to be quite a big change to me, yet I’ve not seen it highlighted (or well documented) so far.

Aside from the GC options noted above, there is a significant change in how logging is handled by the JVM. JEP 158 introduces the Unified Logging system, and this is used by GC logging to provide Unified GC logging (JEP 271). This affects a number of commonly used GC logging command line options as well as some other things.

SEE MORE: Java 9 and beyond: “Modules are very much a feature for the long-term”

To figure out exactly what had changed I extracted the relevant lines from the OpenJDK source code (specifically, the src/share/vm/runtime/globals.hpp file). By doing a diff, I was able to get a list of all the -XX options that had been removed from JDK 8 and all those that had been added to JDK 9. I then wrote a script to use each in turn with a simple app to see what the result of using the options that had been removed from JDK 8 was on JDK 9.

The changes to -XX options can be separated into three groups:

Ignored Command Line Options

If you use one of these, you will get the following warning message, but the JVM will start normally.

Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option; support was removed in 9.0

  • AdaptiveSizePausePolicy
  • CodeCacheMinimumFreeSpace
  • DefaultThreadPriority
  • JNIDetachReleasesMonitors
  • LazyBootClassLoader
  • NmethodSweepCheckInterval
  • NmethodSweepFraction
  • PrintOopAddress
  • ReflectionWrapResolutionErrors
  • StarvationMonitorInterval
  • ThreadSafetyMargin
  • UseAltSigs
  • UseBoundThreads
  • UseCompilerSafepoints
  • UseFastAccessorMethods
  • UseFastEmptyMethods
  • BackEdgeThreshold
  • PreInflateSpin

Deprecated Command-Line Options

These options will issue a warning when the JVM starts, either telling you which option will be used instead by the JVM or telling you which option you should use. Most of these are related to the move to unified GC logging.

Here are two examples of the warning messages:

warning][gc] -XX:+PrintGC is deprecated. Will use -Xlog:gc instead.

Java HotSpot(TM) 64-Bit Server VM warning: Option CreateMinidumpOnCrash was deprecated in version 9.0 and will likely be removed in a future release. Use option CreateCoredumpOnCrash instead.

The table below shows the JDK 8 command line option and the JDK 9 replacement.

JDK 8 Option JDK 9 Replacement
PrintGC -Xlog:gc
PrintGCDetails -Xlog:gc*
CreateMinidumpOnCrash CreateCoredumpOnCrash (suggestion)
DefaultMaxRAMFraction MaxRAMFraction (suggestion)
TraceBiasedLocking -Xlog:biasedlocking=info
TraceClassLoadingPreorder -Xlog:class+preorder=debug
TraceClassResolution -Xlog:class+resolve=debug
TraceMonitorInflation -Xlog:monitorinflation=debug
TraceRedfineClasses -Xlog:redefine+class*=info
TraceSafepointCleanupTime -Xlog:safepoint+cleanup=info
TraceClassLoading -Xlog:class+load=info
TraceLoaderConstraints -Xlog:class+loader+constraints=info
ConvertSleepToYield NONE

Options That Won’t Work

These are the most significant options regarding compatibility. If you have used these in the past and don’t change your command line, your application won’t start. When you use one of these you will get the following error message:

Unrecognized VM option ''
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

Here’s the list of 50 options that won’t work with JDK 9.  Check to see if you’ve used any of these in your command line and startup scripts.

  • AdjustConcurrency
  • CMSCompactWhenClearAllSoftRefs
  • CMSDumpAtPromotionFailure
  • CMSFullGCsBeforeCompaction
  • CMSIncrementalDutyCycle
  • CMSIncrementalDutyCycleMin
  • CMSIncrementalMode
  • CMSIncrementalOffset
  • CMSIncrementalPacing
  • CMSParPromoteBlocksToClaim
  • CMSPrintEdenSurvivorChunks
  • CollectGen0First
  • GCLogFileSize
  • NumberOfGCLogFiles
  • ParallelGCVerbose
  • PrintAdaptiveSizePolicy
  • PrintCMSInitiationStatistics
  • PrintCMSStatistics
  • PrintClassHistogramAfterFullGC
  • PrintClassHistogramBeforeFullGC
  • PrintFLSCensus
  • PrintFLSStatistics
  • PrintGCApplicationConcurrentTime
  • PrintGCApplicationStoppedTime
  • PrintGCCause
  • PrintGCDateStamps
  • PrintGCTaskTimeStamps
  • PrintGCTimeStamps
  • PrintHeapAtGC
  • PrintHeapAtGCExtended
  • PrintJNIGCStalls
  • PrintOldPLAB
  • PrintPLAB
  • PrintParallelOldGCPhaseTimes
  • PrintPromotionFailure
  • PrintReferenceGC
  • PrintTLAB
  • PrintTenuringDistribution
  • TraceDynamicGCThreads
  • TraceGen0Time
  • TraceGen1Time
  • TraceMetadataHumongousAllocation
  • TraceParallelOldGCTasks
  • UseCMSCollectionPassing
  • UseCMSCompactAtFullCollection
  • UseGCLogFileRotation
  • UseMemSetInBOT
  • UseVMInterruptibleIO
  • WorkAroundNPTLTimedWaitHang


Hopefully, this will help you check whether there are any changes you need to make to your application and its configuration as you migrate to JDK 9.

This post was originally published on the Azul Systems blog.

Simon Ritter will be delivering a talk at JAX London which will focus on Lambdas ( introduced in Java 8).

All hail the mighty glow cloud.


Simon Ritter

Simon Ritter is the Deputy CTO of Azul Systems. Simon has been in the IT business since 1984 and holds a Bachelor of Science degree in Physics from Brunel University in the U.K.

Simon joined Sun Microsystems in 1996 and spent time working in both Java development and consultancy. He has been presenting Java technologies to developers since 1999 focusing on the core Java platform as well as client and embedded applications. Now at Azul Systems he continues to help people understand Java and Azul’s JVM products.

comments powered by Disqus