Java 8 introduced String Deduplication that can be enabled by launching JVM with -XX:+UseStringDeduplication
option allowing to save some memory by referencing
I absolutely understand that this does not answer the question, just wanted to mention that jdk-9 introduces one more optimization that is on by default called :
-XX:+CompactStrings
where Latin1 characters occupy a single byte instead of two (via a char). Because of that change many internal methods of String have changed - they act the same to the user, but internally they are faster in a lot of cases.
Also in case of Strings for concatenating two Strings together via the plus sign the javac is going to generate different bytecode.
There is no bytecode instruction that concatenates two Strings together so the javac would generate a
StringBuilder#append
in the back-end. Until jdk-9.
Now the bytecode delegates to
StringConcatFactory#makeConcatWithConstants
or
StringConcatFactory#makeConcat
via the invokedynamic bytecode instruction:
aload_0
1: aload_2
2: aload_1
3: invokedynamic #8, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
8: areturn
How the two strings are concatenated is a Runtime decision now. it could be still a StringBuilder or it could be a concatenation of byte arrays, etc. All you know that this can change and you will get the fastest possible solution.
EDIT
I've just debugged and saw that there are quite a lot of strategies on how to append these Strings:
private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
The default being:
MH_INLINE_SIZED_EXACT
Cases where String de-duplication could be harmful include:
There is a reasonable probability of duplicates, but most strings die in within a couple of GC cycles1 anyway. The de-duplication is less beneficial if the de-duped strings were going to be GC'ed soon anyway.
(This is not about strings that don't survive the first GC cycle. It would make no sense for the GC to even try to de-dup strings that it knows to be garbage.)
We can only speculate as to why the Java team didn't turn on de-duping by default, but they are in a much better position to make rational (i.e. evidence based) decisions on this that you and I. My understanding is that they have access to many large real-world applications for benchmarking / trying out the effects of optimizations. They may also have contacts in partner or customer organizations with similarly large code-bases and concerns about efficiency ... who they can ask for feedback on whether optimizations in an early access release work as expected.
1 - This depends on the value of the StringDeduplicationAgeThreshold
JVM setting. This defaults to 3 meaning that (roughly) a string has to survive 3 minor collections or a major collection to be considered for de-duping. But anyhow, if a string is de-duped and then found to be unreachable shortly afterwards, the de-duping overheads will not be repaid for that string.
If you are asking when you should consider enabling de-duping, my advice would be to try it and see if it helps on a per-application basis. But you need to do some application-level benchmarking (which takes effort!) to be sure that the de-duping is beneficial ...
A careful read of JEP 192 would also help you understand the issues, and make a judgment on how they might apply for your Java application.
At javaperf consulting we have developed an automate which automatically performs corrections in your source code. In fact there is no longer any duplication of strings. The correction rule applies the recommendations of SonarQube and calculates the variable names so that they remain readable in the code. The automate also takes into account the other variables already used to avoid name collisions.