4

サイトでこの質問を読みました Javaメモリプールはどのように分割されていますか? そして、「文字列定数プール」がこれらのセクターのどれに属しているのか疑問に思っていましたか?

またString、プール内のリテラルはGCされますか?

このintern()メソッドはString、プールからリテラルのベース リンクを返します。

プールがGCされた場合、文字列プールのアイデアにとって逆効果ではありませんか? 新しいStringリテラルが再び作成され、GC が無効になります。

(リテラルの特定のセットのみがプールに存在すると想定しています。それらは決して時代遅れになることはなく、遅かれ早かれ再び必要になります)

4

5 に答える 5

2

私の知る限り、文字列リテラルは非ヒープ JVM メモリの "Perm Gen" 部分に配置されます。Perm Gen スペースは、フル GC の実行中にのみ検査されます (パーシャルではありません)。

初期の JVM では (確信が持てなかったのでこれを調べる必要があったことを認めます)、String Pool 内の String リテラルは GC されることはありませんでした。新しい JVM では、WeakReferencesを使用してプール内の文字列を参照するため、インターンされた文字列は実際に GC を取得できますが、フル ガベージ コレクションの間のみです。

于 2012-06-08T16:18:45.023 に答える
1

文字列プーリング

文字列プーリング (文字列の正規化とも呼ばれます) は、複数の String オブジェクトを、値は等しいが ID が異なる単一の共有 String オブジェクトに置き換えるプロセスです。この目標を達成するには、独自のマップ (要件に応じてソフト参照または弱参照を使用する可能性があります) を保持し、マップ値を正規化された値として使用します。または、JDK が提供する String.intern() メソッドを使用できます。

Java 6 の時点で、 String.intern() を使用することは、プーリングが制御不能になった場合に OutOfMemoryException を取得する可能性が高いため、多くの標準で禁止されていました。文字列プーリングの Oracle Java 7 実装は大幅に変更されました。詳細はhttp://bugs.sun.com/view_bug.do?bug_id=6962931および http://bugs.sun.com/view_bug.do?bug_id=6962930で確認できます 。

Java 6 の String.intern()

古き良き時代、インターンされたすべての文字列は PermGen に格納されていました。これは、ロードされたクラスと文字列プールを格納するために主に使用されるヒープの固定サイズの部分です。明示的にインターンされた文字列に加えて、PermGen 文字列プールには、プログラムで以前に使用されたすべてのリテラル文字列も含まれていました (ここで重要な言葉が使用されます。クラスまたはメソッドがロード/呼び出されなかった場合、その中で定義された定数はロードされません)。

Java 6 のこのような文字列プールの最大の問題は、その場所 (PermGen) でした。PermGen は固定サイズで、実行時に拡張できません。-XX:MaxPermSize=96m オプションを使用して設定できます。私の知る限り、デフォルトの PermGen サイズは、プラットフォームによって 32M から 96M の間で異なります。サイズを大きくすることはできますが、サイズは固定されたままです。このような制限により、String.intern を非常に慎重に使用する必要がありました。このメソッドを使用して制御されていないユーザー入力をインターンしない方がよいでしょう。そのため、Java 6 の時点での文字列プーリングは、ほとんどが手動で管理されたマップに実装されていました。

Java 7 の String.intern()

Oracle のエンジニアは、Java 7 の文字列プール ロジックに非常に重要な変更を加えました。文字列プールはヒープに再配置されました。これは、別の固定サイズのメモリ領域によって制限されなくなったことを意味します。すべての文字列は、他のほとんどの通常のオブジェクトと同様にヒープに配置されるようになりました。これにより、アプリケーションのチューニング中にヒープ サイズのみを管理できます。技術的には、これだけでも、Java 7 プログラムで String.intern() を使用することを再検討する十分な理由になる可能性があります。しかし、他にも理由があります。

文字列プールの値はガベージ コレクションです

はい、JVM 文字列プール内のすべての文字列は、プログラム ルートからの参照がない場合、ガベージ コレクションの対象となります。これは、議論されている Java のすべてのバージョンに適用されます。これは、インターンされた文字列が範囲外になり、それに対する参照が他にない場合、JVM 文字列プールからガベージ コレクションされることを意味します。

ガベージ コレクションの対象となり、ヒープに常駐する JVM 文字列プールは、すべての文字列にとって適切な場所のようですね。理論的には真実です。未使用の文字列はプールからガベージ コレクションされます。使用済みの文字列を使用すると、入力から等しい文字列を取得した場合に備えてメモリを節約できます。完璧なメモリ節約戦略のようですか?ほぼそうです。決定を下す前に、文字列プールがどのように実装されているかを知っておく必要があります。

ソース。

于 2013-11-28T12:21:39.087 に答える
1

String.intern() の JavaDoc を読んでも実装のヒントにはなりませんが、このページによると、インターンされた文字列は弱い参​​照によって保持されます。これは、インターンされた文字列を保持するリポジトリを除いて、インターンされた文字列への参照がないことを GC が検出した場合、GC はそれらを収集できることを意味します。もちろん、これは外部コードに対して透過的であるため、独自の弱い参照を使用していない限り、ガベージ コレクションについては決してわかりません。

于 2012-06-08T16:26:03.083 に答える
0

文字列は不変ですが、Java の他のオブジェクトと同様にオブジェクトです。オブジェクトはヒープ上に作成され、文字列も例外ではありません。そう、Strings that are part of the "String Literal Pool" still live on the heap, but they have references to them from the String Literal Pool.

詳細については、このリンクを参照してください

      `http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html`

新たに編集:

public class ImmutableStrings

                {

                    public static void main(String[] args)

                   {
                        String one = "someString";
                        String two = new String("someString");

                        one = two = null;
                    }
                 }

メイン メソッドが終了する直前に、ガベージ コレクションに使用できるオブジェクトはいくつありますか? 0? 1? 2?

答えは 1 です。ほとんどのオブジェクトとは異なり、文字列リテラルは常に文字列リテラル プールから参照されます。つまり、それらは常にそれらへの参照を持っているため、ガベージ コレクションの対象にはなりません。

ローカル変数の 1 つまたは 2 つが String オブジェクトを参照しておらず、String Literal Pool からの参照が残っています。したがって、オブジェクトはガベージ コレクションの対象にはなりません。オブジェクトは、intern() メソッドを使用して常に到達可能です。

于 2012-06-08T16:37:38.103 に答える
0

Stringリテラルは実行時にプールに作成されません。それらが GC されるかどうかは確かではありませんが、2 つの理由からそうならないのではないかと考えています。

  • リテラルが使用されなくなる一般的なケースを検出するのは非常に複雑です。
  • パフォーマンスのために格納されている静的コード セグメントが存在する可能性があります。残りのデータはその周りに構築されている可能性が高く、境界も静的です
于 2012-06-08T16:19:34.893 に答える