2016-07-15 6 views
19

あなたがJVMはどのように内部ストリング部分文字列を再利用しますか?

for (condition) { 
    String s = "hi there"; 
} 

ちょうど1 Stringインスタンスは、各反復で新しいインスタンスを作成しますString s = new String("hi there");とは異なり、すべての反復で作成されていることを確認した場合、私は承知しています。

しかし、ジョシュア・ブロックからの効果的なJavaの読み:第2章5項(20ページ)には、状態:

はさらに、対象が同じで実行されている他のコードによって を再利用されることが保証されます仮想マシンにはと同じ文字列リテラル[JLS, 3.10.5]が含まれています。

が同じ文字列リテラルことに起こる言っていない私の知る限り、それはが含まれていますと言います。

[JLS, 3.10.5]を読むことはこれに関する正確な参照を見つけることができず、私は疑いがあります。

String s1 = "hi "; 
String s2 = "there"; 
String s3 = "hi there"; 

作成されたどのように多くのインスタンス:このスニペットを与える

  • 3つのインスタンス(したがって、フレーズは実際には正確ではありません)。
  • 2の場合、s1s2(当時s3s1s2の参照を再利用して作成されます)
+1

彼はおそらく "仮想マシンに.."という文字列が含まれていないことを意味します。 –

+1

私はよくわからないので、答えではなくコメントです。しかし、私は "含む"は部分的に間違っていると思うし、あなたの例は実際に3つのインスタンスを生成します。 – glglgl

+0

@glglglは実際には*私の論理が言うことですが、 's1' +' s2'への参照として 's3'を作成するのに十分スマートなJVMにすることができますか? –

答えて

17

JLSは一切のサブ文字列のいずれかの再利用を保証するものではありません。ここに「含む」とは、クラスのにはまったく同じ文字列リテラルが記述されていることを意味しています。 ではなく、が「部分文字列」の意味で使用されています。

+2

具体的には、**同じ文字列リテラル** "_(emphasis mine)を含む他のコード[..] –

+1

*サブストリングの再利用を保証しない*は時々発生する可能性があることを意味しますか? –

+3

@ JordiCastilla:現行のVMは部分文字列を再利用しているとは思えませんが、可能です(例えば、2つの文字列が互いに部分文字列であった場合、OpenJDKの以前の反復では、別の 'String'インスタンスも見ていて、それが起こっているかどうかを検出するための公開APIはありません(リフレクショントリッキーがなくてもわかりません)。 –

3

各クラスファイルには、そのクラス内で使用されるすべての文字列リテラルまたはその他の定数のリストが含まれます(命令ストリームに埋め込まれた小数値定数を除く)。一覧の項目19が文字列リテラル"Freddy"で、ローカル変数Fredのインデックスが6の場合、Fred="Freddy";のバイトコードはldc 19/astore 6となる可能性があります。

クラスがロードされると、システムはすべての定数と参照タイプのものについて、それによって識別されたオブジェクトの表を作成します。文字列リテラルのインスタンスが存在しないことがわかっている場合、システムは内部テーブルに1つを追加し、そのテーブルへの参照を格納します。マシンコードを生成する場合、ldc 19は、適切な参照をロードする命令に置き換えられます。

重要なのは、コードの任意のクラスの実行の時間によって、オブジェクトはその中のすべての文字列リテラルのために作成されているということですので、Fred="Freddy";のような文は単にFreddyを含む既存のStringオブジェクトへの参照が格納されます新しいStringオブジェクトを作成するのではなく、s3s1s2インスタンスを再利用する場合

2

、次いでs3は、物理的に連続した文字列として表現されない、むしろString Sオブジェクトの複合Stringあろう。

このような文字列ベースのアクセスで個々の文字にアクセスすることによるパフォーマンスへの影響が実際にはインデックス値と最初の文字列のサイズを比較し、次に2番目の文字列のインデックスになるオフセットの計算などが考えられます。 。

実際に、意味を作ることができ、反対は:唯一の基礎となる文字列がちょうどそれらの長さと、その文字列内の最初の文字のアドレスを格納することができ"hi there"s3)、およびs1s2のために割り当てることができます。しかし、私は、組み込み可能な候補を特定することはjvmにとって複雑で高価な作業であり、コストは潜在的な利益よりも大きいと考えています。

+1

Java 7より前のバージョンでは、 'substring'メソッドは、元のStringの文字配列に裏打ちされたStringを返すように実装されていましたが、それは良いよりも大きな害を引き起こしたため削除されました例えば、小さなサブストリングへの参照を保持することで生き続ける) – Hulk

+1

@Hulk:[Java7update6の変更](http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4513622)です。それはgc問題だけではありません。単一の操作、すなわち 'substring'の目的のために、すべての文字列に' offset'と 'length'フィールドを渡す必要があります。さらに、最近のJVMの文字列重複排除機能は、「value」フィールド上の単一の「cas」で十分であるため、単純化されたオブジェクトレイアウトから利益を得ます。 – Holger

関連する問題