6

String が作成されたときのメモリ割り当てに関する多くの矛盾する記事を読みました。new 演算子はヒープに文字列を作成し、文字列リテラルは文字列プール [ヒープ] に作成するという記事もあれば、new 演算子はヒープにオブジェクトを作成し、文字列プールに別のオブジェクトを作成するという記事もあります。

これを分析するために、String char 配列と String オブジェクトのハッシュコードを出力する以下のプログラムを作成しました。

import java.lang.reflect.Field;

public class StringAnalysis {

    private int showInternalCharArrayHashCode(String s)
            throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException {
        final Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        return value.get(s).hashCode();
    }

    public void printStringAnalysis(String s) throws SecurityException,
            IllegalArgumentException, NoSuchFieldException,
            IllegalAccessException {
        System.out.println(showInternalCharArrayHashCode(s));

        System.out.println(System.identityHashCode(s));

    }

    public static void main(String args[]) throws SecurityException,
            IllegalArgumentException, NoSuchFieldException,
            IllegalAccessException, InterruptedException {
        StringAnalysis sa = new StringAnalysis();
        String s1 = new String("myTestString");
        String s2 = new String("myTestString");
        String s3 = s1.intern();
        String s4 = "myTestString";

        System.out.println("Analyse s1");
        sa.printStringAnalysis(s1);

        System.out.println("Analyse s2");
        sa.printStringAnalysis(s2);

        System.out.println("Analyse s3");
        sa.printStringAnalysis(s3);

        System.out.println("Analyse s4");
        sa.printStringAnalysis(s4);

    }

}

このプログラムは、次の出力を出力します。

Analyse s1
1569228633
778966024
Analyse s2
1569228633
1021653256
Analyse s3
1569228633
1794515827
Analyse s4
1569228633
1794515827

この出力から、文字列がどのように作成されたかに関係なく、文字列が同じ値を持つ場合、それらは同じ文字配列を共有することが非常に明確です。

今私の質問は、この chararray はどこに保存されているのか、ヒープに保存されているのか、それとも permgen に保存されているのかということです。また、ヒープ メモリ アドレスと permgen メモリ アドレスを区別する方法も知りたいです。

permgen に保存すると、限られた貴重な permgen スペースを使い果たしてしまうので、大きな問題があります。char配列がpermgenではなくヒープに格納されている場合、文字列リテラルもヒープスペースを使用していることを意味します[これは私が読んだことがないものです]。

4

3 に答える 3

3

文字列ソースから

 public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

このコンストラクターで作成された文字列が元の文字列と char 配列 (値) を共有していることは明らかです。

API はこの共有を保証しないことに注意することが重要です。

新しく作成された String オブジェクトを初期化して、引数と同じ文字シーケンスを表すようにします。つまり、新しく作成された文字列は引数文字列のコピーです。オリジナルの明示的なコピーが必要でない限り、文字列は不変であるため、このコンストラクターの使用は不要です。

たとえば、String.substring は char 配列を元の文字列と共有するために使用されていましたが、Java 1.7 の最新バージョンでは、String.substring は char 配列のコピーを作成します。

于 2013-04-22T17:20:26.877 に答える