web-dev-qa-db-ja.com

Java 8文字列重複排除とString.intern()

Java 8 update 20 for String deduplication( 詳細 )の機能について読んでいますが、これが基本的にString.intern()になるかどうかはわかりません。廃止されました。

このJVM機能にはG1ガベージコレクターが必要であることを知っていますが、これは多くの人にとってオプションではないかもしれませんが、G1GCを使用していると仮定すると、自動重複排除の違い/利点/欠点はありますかJVMによってvs手動で文字列をinternする必要がある(1つの明らかなものは、intern()の呼び出しでコードを汚染する必要がないという利点です)?

OracleがG1GCをJava 9)のデフォルトGCにする可能性があることを考えると、これは特に興味深いものです。

18
Hilikus

この機能を使用すると、1000個の異なるStringオブジェクトがあり、すべて同じコンテンツ_"abc"_である場合、JVMはそれらを内部で同じ_char[]_を共有させることができます。ただし、1000個の異なるStringオブジェクトがまだあります。

intern()を使用すると、Stringオブジェクトが1つだけになります。したがって、メモリの節約が懸念される場合は、intern()の方が適しています。スペースとGC時間を節約できます。

ただし、前回聞いたときは、intern()のパフォーマンスはそれほど良くありません。 ConcurrentHashMap ...を使用する場合でも、独自の文字列キャッシュを用意する方がよい場合がありますが、確実にベンチマークする必要があります。

11
ZhongYu

コメントの参照として、以下を参照してください: http://Java-performance.info/string-intern-in-Java-6-7-8/ 。これは非常に洞察に満ちた参考資料であり、多くのことを学びましたが、その結論が必ずしも「1つのサイズですべてに適合する」かどうかはわかりません。それぞれの側面は、独自のアプリケーションのニーズによって異なります。現実的な入力データを測定することを強くお勧めします。

主な要因は、おそらくあなたが何を管理しているかに依存します:

  • GCの選択を完全に制御できますか?たとえば、GUIアプリケーションでは、シリアルGCを使用するための強力なケースがまだあります。 (プロセスの合計メモリフットプリントははるかに少ない-適度に複雑なアプリの場合は約1GBに対して400MBと考え、使用量が一時的に急増した後など、メモリを解放する意欲がはるかに高くなります)。したがって、それを選択するか、ユーザーにオプションを提供することができます。 (ヒープが小さいままの場合、一時停止は大したことではありません)。

  • コードを完全に制御できますか? G1GCオプションは、編集できないサードパーティのライブラリ(およびアプリケーション!)に最適です。

2番目の考慮事項(@ZhongYuの回答による)は、_String.intern_はStringオブジェクト自体を重複排除できるのに対し、G1GCは必然的にプライベート_char[]_フィールドのみを重複排除できるということです。

3番目の考慮事項は、CPU使用率です。たとえば、ラップトップのバッテリー寿命への影響がユーザーにとって懸念される場合などです。 G1GCは、ヒープの重複排除専用の追加スレッドを実行します。たとえば、Eclipseを実行するためにこれを試してみたところ、起動後にCPUアクティビティが最初に増加することがわかりました(1〜2分と考えてください)が、「使用中」の小さなヒープに落ち着き、明らかではありません(目だけ-タスクマネージャーのボール)CPUオーバーヘッドまたはその後の速度低下。したがって、CPUコアの特定の割合が、大量のメモリチャーンの重複排除(中?後?)期間に使用されると思います。 (もちろん、String.interneverywhereを呼び出すと、同等のオーバーヘッドが発生する可能性があります。これもシリアルで実行されますが、...)

おそらくどこでも文字列の重複排除は必要ありません。おそらく、次のような特定のコード領域しかありません。

  • 長期的なヒープ使用量に本当に影響しますおよび
  • 重複する文字列の割合を高くする

_String.intern_を選択的に使用することにより、コードの他の部分(一時的または半一時的な文字列を作成する可能性があります)は代償を払いません。

そして最後に、Guavaユーティリティのクイックプラグ: Interner 、which:

他の不変タイプのString.intern()と同等の動作を提供します

文字列にも使用できます。メモリはおそらくパフォーマンスの最大の懸念事項である(そしてそうあるべきである)ので、これはおそらく頻繁には当てはまりません。ただし、ホットスポット領域から速度のすべての低下を絞り出す必要がある場合、私の経験では、Javaベースの弱参照です。 HashMapソリューションは、jvmオプションを調整した後でも、JVMのString.intern()のC++実装よりもわずかですが一貫して高速に実行されます。 (そしてボーナス:異なる入力にスケーリングするためにJVMオプションを調整する必要はありません。)

4
Luke Usherwood

ターゲットオーディエンスに関する別の決定要因を紹介したいと思います。

  • 多くの異なるライブラリ/フレームワークで構成されたシステムを持ち、それらのライブラリの内部開発に影響を与える能力が低いシステムインテグレータの場合、メモリに問題がある場合は、StringDeDuplicationがすぐに勝者になる可能性があります。これはJVM内のすべての文字列に影響しますが、G1はそれを行うために空き時間のみを使用します。別のパラメーター(StringDeduplicationAgeThreshold)を使用して重複排除を計算するときに、微調整することもできます。
  • 自分のコードをプロファイリングする開発者にとって、String.internはもっと興味深いかもしれません。インターンを呼び出すかどうか、いつ呼び出すかを決定するには、ドメインモデルを慎重に検討する必要があります。経験則として、文字列に列挙されたセットの種類(国名、月、曜日など)など、限られた値のセットが含まれることがわかっている場合は、インターンを使用できます。
3
Jaime Casero