Java 9 Performance Improvements — Getting Started With Java Spring
Take a look at how some of the performance improvements and changes in Java 9 differ from Java 8.
Join the DZone community and get the full member experience.
Join For FreeIn my previous article, I wrote about the Modularity System, which was introduced in Java 9. This was the most major feature of the release, but there are other significant ones which worth to mention. With this writing, I would like to continue the Java evolution line by taking a glance about the main Java 9 features according to the performance improvements.
Java 9 Feature: Performance Improvements
Garbage Collector Deprecations
In Java 9, the most significant performance upgrade was concerned with the Garbage Collection. They introduced a new default one and removed the olds.
This means that if you used one of them in your application you have to be aware of that if you switch to Java 9.
If you use the -XX:+UseConcMarkSweepGC Option, it will throw you a warning that is deprecated and will likely be removed in a future release. However, it was a good reason for the depreciation, there is a much better alternative of CMS Garbage Collector in the new JDK. It is called the G1 GC.
G1 Garbage Collector
- G1: Garbage first
- Introduced in JDK 6, now default in JDK 9
- Replaces Concurrent Mark Sweep GC (CMS)
Be aware of this change because it heavily affects the Garbage collection of your code. Usually, it makes it faster, but in some unique cases, it can cause some performance regressions. So keep an eye on it.
The Old Way of Garbage Collection
Used to in Java runtime, the different generation of GCs used the same philosophy.
The heap was divided into the following three categories:
- Eden: This where the Objects born. Like in the Bible.
- Survivor: If an object lives long enough, it will go into the Survivor area.
- Tenured: If it getting really old it will be moved into the Tenured area.
Objects lives in the Tenured area considered more stable than the previous ones.
In the Eden area, the Objects born and die more frequently than the other ones. It enables the GC to treat these areas differently.
Therefore, in the Eden, the Garbage Collection must occur more frequently than the Survivor or the Tenured region.
While this Garbage Collection works fairly well, it has some drawbacks:
- Long "stop-the world "GC pauses. The whole was on hold while the Garbage Collection finish. If the heap size raises it became a bigger and bigger problem.
- Difficult to tune
G1 Garbage Collector
The main differences according to the previous ones:
Incremental GC
However, the three main region types remained. Each of them is divided into separate smaller regions. The GC can decide to skip regions and only collect specific ones in the cycle. By doing so, it can keep response times low.
Parallel Marking
Besides the Garbage Collection phase, it has a parallel marking phase. As the application runs, the G1GC check the regions which should be garbage collected and marks them. In the next GC phase, it will be Garbage Collected.
Note that in both previous phases it can run parallel beside the main thread.
Designing for Large Heaps
The setup using small regions works better in large heaps, unlike previous GCs. It never scans the whole heap to Garbage Collection.
Low Pause Times, Tunable Pause Goals
Hence the above point lowers pause times. Furthermore, we can see that each pause step cannot exceed for example 200ms.
It lowers pause times but on the other hand, it needs more CPU time to run in parallel.
Automatic tuning:
Heap region size: Can determine the optimum size of the regions.
Parallel threads: Can pick a good default for the parallel thread count depending on the CPU.
Pause time interval: G1GC tries to set automatically that what should be a minimum interval when Garbage collection can happen.
It's important to notice that you override this auto tunings through option value settings.
For example: -XX:MaxGCPauseMillis=200
String deduplication
It is not enabled by default but you can set it through the -XX:+G1EnableStringDeduplication
This is useful in String heavy applications. It is not anomalous that the Strings are reserve the most size in the heap.
If this flag is enabled G1GC checks if there are any duplicated strings in the heap and it points the same ones to one shared reference.
Turning on this option can reduce memory pressure.
String Performance Updates
There are more performance optimizations according to strings in Java 9. Let us see it next.
Compact Strings
It has two main goals:
- Lower memory usage
- Effective immediately without code changes
Before Java 9
Strings were stored in a characher array which consumed up to two-byte character.
After Java 9
Now the Strings are stored in in a Byte array.
It has an additional byte flag. The compiler checks are the String contains only ASCII characters. If so it set it to 0 and the characters are interpreted to one byte.
If it set 1 they will consume up to two bytes, like before.
So if your String contains only ASCII characters, it will only consume half of the space than before Java 9.
Some benchmarks showed that a regular application can save from 10 up to 50% of heap size because of compact strings.
The nice thing about this is that completely works inner the String class, so it transparent from the developer's eye.
String Concatenation Changes
Main goals:
- Change concatenation translation strategy
- Groundwork for future improvements
Before Java 9
Let us see a simple string concatenation. Before Java 9, the compiler compiled it to a series of append calls of a StringBuilder
instance.
After Java 9
Now the compiler emits Invokedynamic bytecode, which means that the function which called is determined in runtime rather than compile time. This is the essence of the implementation of the lambda expressions as well, introduced in Java 8.
It is a fairly new bytecode which when executed allows late binding to an actual implementation method.
Hence, the expression to concat Strings is not determined in compile time, but runtime.
Although the performance improvement of this is neglectable. It opens the door to change the behavior of a given code by simply updating the JVM to a newer version. No recompiling needed.
Using a stable bytecode rather than a precompiled method ensures future improvement possibilities.
This will not improve your performance immediately not like compact Strings.
Summary
I hope you enjoyed my article. For me, Java 9 features is a very interesting topic and hopes it will be a piece of valuable knowledge for the vast majority as well.
I would like to return with some other writing according to Java in the near future, so stay tuned!
To learn more about JDK 9 in depth I recommend you the following video course: What's New in Java 9.
Published at DZone with permission of Zoltan Raffai, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments