web-dev-qa-db-ja.com

Java 8 UseStringDeduplicationをJVMで有効にしたくないのはなぜですか?

Java 8では、重複を保持するのではなく、同様のStringオブジェクトを参照することでメモリを節約できる-XX:+UseStringDeduplicationオプションでJVMを起動することで有効にできる文字列重複排除が導入されました。もちろん、その有効性はStringsの使用状況に応じてプログラムごとに異なりますが、一般的に、ほとんどのアプリケーション(すべてではないにしても)に有益であると考えることができると言っても安全だと思います。

デフォルトで有効になっていないのはなぜですか?重複排除に関連するコストのためか、それともG1GCがまだ新しいと考えられているためですか?

重複排除を使用したくないEdgeのケースはありますか(または存在する可能性がありますか)?

22
Ninetou

文字列の重複排除が有害になる可能性がある場合は次のとおりです。

  • 文字列はたくさんありますが、重複の可能性は非常に低くなります。重複を探す時間のオーバーヘッドと重複排除データ構造のスペースのオーバーヘッドは返されません。
  • 重複する可能性はかなりありますが、ほとんどの文字列は数回のGCサイクルで消滅します1 とにかく。とにかく重複排除された文字列がすぐにGCされる場合、重複排除はあまり有益ではありません。

    (これは、最初のGCサイクルに耐えられない文字列に関するものではありません。GCがtryで文字列を重複排除することは意味がありませんゴミであることを知っていること。)

Javaチームがデフォルトで重複排除を有効にしなかった理由について推測することはできますが、この点に関して合理的な(エビデンスに基づいた)決定を下すのにはるかに良い立場にあります。私と私の理解では、最適化の効果をベンチマーク/試用するために、多くの大規模な実世界のアプリケーションにアクセスできます。また、同様に大きなコードベースと効率に関する懸念を持つパートナーまたは顧客組織の連絡先があります。早期アクセスリリースの最適化が期待どおりに機能するかどうかについてフィードバックを求めることができる人。

1-これは、StringDeduplicationAgeThreshold JVM設定の値に依存します。これは、デフォルトで3になります。これは、重複除去を検討するために、文字列が3つのマイナーコレクションまたはメジャーコレクションに耐えなければならないことを意味します。しかし、とにかく、文字列が重複排除され、その後すぐに到達不能であることが判明した場合、重複排除のオーバーヘッドはその文字列に対して返済されません。


重複除外を有効にすることを検討する必要がある場合は、アプリケーションごとにを有効にして確認することをお勧めします。ただし、重複排除が有益であることを確認するには、アプリケーションレベルのベンチマークを実行する必要があります(努力が必要です!)。

JEP 192 を注意深く読むと、問題を理解し、Javaアプリケーションにどのように適用されるかを判断できます。

25
Stephen C

これは質問に答えないことを完全に理解しています、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

18
Eugene