During the past few days I have been fighting with an issue
happening after migrating from JRE 1.6 (1.6.0_30) to JRE 1.7 (1.7.0_65).
I want to share this experience with you, so that (hopefully) you don’t have to deal with it ;)
I want to share this experience with you, so that (hopefully) you don’t have to deal with it ;)
User Experience:
After some time the application was running, it started
becoming slow, though the CPU load was low. The user experienced a latency in
terms of responsiveness of the component.
Analysis on Code Cache:
After some research and internal discussions with colleagues,
I started concentrating on the JIT compilation and the Code Cache:
- JRE 1.7 enable by default the Code Cache flushing, which should (theoretically) improve performance of your application, since it dispose old JITted code in favour of new one (speculative flushing).
Unfortunately, the Code Cache flushing seems not to work properly in
Java 1.7 (while in Java 1.6 it works fine)
I started profiling my application (using JConsole: Memory->Code Cache),
monitoring the Code Cache (which default size is 48MB, -XX:ReservedCodeCacheSize=48M)
and I have discovered that my application uses the entire Code Cache heap.
- JRE 1.6: after Code Cache fills, the bytecode compilation will stop (by default) switching into interpreted mode.
- JRE 1.7: after Code Cache fills, Code Cache flushing starts, marking older methods to be potentially eligible for flushing in favor of newer methods. Actually it seems that after the Code Cache flushing, JIT compilation stops at all causing degradation in performance (neither old or new code is compiled anymore)
Since the Code Cache flushing is disabled by default in jre 1.6, I have enabled it and performed a parallel test (for comparison) with both jre 1.6 and jre 1.7.
Here are the jvm flags used for the test:
-XX:ReservedCodeCacheSize=48M (default)
-XX:+UseCodeCacheFlushing (default only in jre 1.7)
Below you can find a test executed with jre 1.6 and
jre 1.7:
Note: I have seen that in jre 1.7, after sometimes the code compilation starts again (after reaching a very low level, for example 3MB)
JRE 1.8:
This issue is not experienced using jre 1.8, in which the flushing algorithm seems to be changed: the flushing starts before getting the code cache full.
Temporary solution:
A workaround for this problem would be increasing the Code Cache
size and be sure the Code Cache flushing does not happen . In my application
the Code Cache size average seems to be 55MB, so I solved by setting it to
80MB.
The following JVM option can be used:
-XX:ReservedCodeCacheSize=80M
To enable the Code Cache flushing in JRE 1.6 you can set the
following option:
-XX:+UseCodeCacheFlushing
Solution:
At the end, it seems to be related to the following issue, and fixed in JRE 1.8 (hs25):
I think this is a big compatibility issue as it comes out when migrating from jre6 to jre 7.
Question: This fix has been done on Apr-13 on jre 1.8. Why at the present (Jul-14) this fix has never been ported into jre 1.7?
I have contacted Oracle and opened a bug report for this to be sure this issue is related to the known one.
References:
Some reference to understand how the Code Cache works can be
found here:


Good news: It seems Oracle has taken into account my request and they are going to fix this in the next release of java 7u80
RispondiEliminahttps://bugs.openjdk.java.net/browse/JDK-8051955