Java 8では、重複を保持するのではなく、同様のString
オブジェクトを参照することでメモリを節約できる-XX:+UseStringDeduplication
オプションでJVMを起動することで有効にできる文字列重複排除が導入されました。もちろん、その有効性はStrings
の使用状況に応じてプログラムごとに異なりますが、一般的に、ほとんどのアプリケーション(すべてではないにしても)に有益であると考えることができると言っても安全だと思います。
デフォルトで有効になっていないのはなぜですか?重複排除に関連するコストのためか、それともG1GCがまだ新しいと考えられているためですか?
重複排除を使用したくないEdgeのケースはありますか(または存在する可能性がありますか)?
文字列の重複排除が有害になる可能性がある場合は次のとおりです。
重複する可能性はかなりありますが、ほとんどの文字列は数回のGCサイクルで消滅します1 とにかく。とにかく重複排除された文字列がすぐにGCされる場合、重複排除はあまり有益ではありません。
(これは、最初のGCサイクルに耐えられない文字列に関するものではありません。GCがtryで文字列を重複排除することは意味がありませんゴミであることを知っていること。)
Javaチームがデフォルトで重複排除を有効にしなかった理由について推測することはできますが、この点に関して合理的な(エビデンスに基づいた)決定を下すのにはるかに良い立場にあります。私と私の理解では、最適化の効果をベンチマーク/試用するために、多くの大規模な実世界のアプリケーションにアクセスできます。また、同様に大きなコードベースと効率に関する懸念を持つパートナーまたは顧客組織の連絡先があります。早期アクセスリリースの最適化が期待どおりに機能するかどうかについてフィードバックを求めることができる人。
1-これは、StringDeduplicationAgeThreshold
JVM設定の値に依存します。これは、デフォルトで3になります。これは、重複除去を検討するために、文字列が3つのマイナーコレクションまたはメジャーコレクションに耐えなければならないことを意味します。しかし、とにかく、文字列が重複排除され、その後すぐに到達不能であることが判明した場合、重複排除のオーバーヘッドはその文字列に対して返済されません。
重複除外を有効にすることを検討する必要がある場合は、アプリケーションごとにを有効にして確認することをお勧めします。ただし、重複排除が有益であることを確認するには、アプリケーションレベルのベンチマークを実行する必要があります(努力が必要です!)。
JEP 192 を注意深く読むと、問題を理解し、Javaアプリケーションにどのように適用されるかを判断できます。
これは質問に答えないことを完全に理解しています、jdk-9がデフォルトで呼び出されるもう1つの最適化を導入することを言及したいだけです:
-XX:+ CompactStrings
ここで、Latin1文字は、2文字ではなく1バイトを使用します(charを使用)。その変更により、Stringの多くの内部メソッドが変更されました-それらはユーザーに対して同じように機能しますが、内部的には多くの場合より高速です。
また、プラス記号を使用して2つの文字列を連結する文字列の場合、javacは異なるバイトコードを生成します。
2つの文字列を連結するバイトコード命令はないため、javacは
StringBuilder#append
バックエンドで。 jdk-9まで。
バイトコードは、
StringConcatFactory#makeConcatWithConstants
または
StringConcatFactory#makeConcat
invokedynamicバイトコード命令を介して:
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
2つの文字列がどのように連結されるかは、現在のランタイムの決定です。まだStringBuilderであるか、バイト配列の連結などである可能性があります。これが変更される可能性があり、可能な限り高速なソリューションが得られることをご存知です。
[〜#〜] edit [〜#〜]
デバッグしたばかりですが、これらの文字列を追加する方法には非常に多くの戦略があることがわかりました。
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
}
デフォルトは次のとおりです。
MH_INLINE_SIZED_EXACT