16

String.intern()メソッドがJavaでどのように実装されているかを調べるために、少し調査を行いました。

Open JDK 6 の Intern プールの C++ 実装を調べたところ、単純なHashSet. 私にとっては、誰かがインターンをしようとしているときにString、次のステップを実行する必要があることを意味しました。

  1. 指定されたハッシュコードを見つけるString
  2. 適切なバケットを見つける
  3. 指定された文字列をバケット内の他のすべての文字列と比較します。このステップの前に、バケット内に 0 個の文字列、1 個の文字列、または多数の文字列が存在する可能性があります。したがって、指定された文字列が以前にバケットに入れられている場合、少なくとも 1 つの比較が行われます (これが最良のケースです。もちろん、多くの衝突があった可能性があり、他の多くの文字列がバケットに含まれています)。
  4. String がバケットで見つかった場合は、intern()メソッドによって返される必要があります
  5. 文字列がバケットに見つからない場合は、バケットに入れ、intern()メソッドによって返す必要があります

str1.intern() == str2.intern()非常に多くの人が、それは よりも速いと言っていstr1.equals(str2)ます。

しかし、それが速くなる理由がわかりません。

ご覧のとおりstr1.equals(str2)、メソッドで char ごとに比較する 2 つの文字列が常に存在しますString.equals()

の場合str1.intern() == str2.intern()、プールとの間で文字列を取得または格納するために必要な比較の数は?

そのため、文字列を比較str1.intern() == str2.intern()するために使用する場合でも、==前述の比較など、多くの追加アクションがあります。

それを理解したとき、ベンチマークテストを行うことにしました。

最初の結果は、str1.intern() == str2.intern()が よりも速いことを示していましたstr1.equals(str2)

この動作は、String.intern()メソッドがネイティブであるため、毎回解釈されるべきではなくString.equals()、Java メソッドであることが原因でした。

そこで、-Xcompオプションを使用して、JVM が開始時にすべてのコードをコンパイルするようにすることにしました。

その後はインターン以上の速さを見せた。

Java 6 および 7 でテストしました。

私の質問は、文字列比較の高速化をインターンするときに状況を見たことがありますか? はい、どうしてですか?

それともintern()、より多くの空きメモリを節約するのに役立つのでしょうか?

4

2 に答える 2

7

String.intern()メモリ使用量を減らすためのものです。

メモリ内に同じ文字列の複数のコピーが多数ある場合にのみ、インターンされた文字列を使用します (存在する場合)。文字列をインターンすることにより、これらすべてのコピーが同じ参照を使用します。

同じ文字列のコピーが何百万もある場合にのみ、文字列のインターンが役立つのを見てきました。

あらゆる種類の最適化と同様に、パフォーマンスまたはメモリの問題が発生し、それがボトルネックであることを検出できるようにプロファイリングした後にのみ実行してください。

文字列インターンの詳細については、このブログ投稿を参照してください。

于 2014-04-07T15:37:54.910 に答える
3

str1.intern() == str2.intern()なぜ速いかもしれないかについてのあなたの質問に:

これがString.equals()実装です - ご覧のとおり、比較する文字列によっては非常に非効率的である可能性があります。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

あなたのステップはもっと速くなるかもしれません:
1) hashCode() は、その不変性のために任意の文字列に対して一度計算され、かなり高速です
2) バケットが O(1) であることを見つけます
3) あなたの文字列を同じバケット内の他のものと比較します - そこにいくつかあるかもしれませんが、それでもequals()
4) および 5)よりも高速である必要があります。

また、上記の操作は文字列に対して 1回だけ実行する必要があることを忘れないでください。一度実行するとintern()、最初の比較から結果が返されます。

于 2014-04-07T16:01:58.303 に答える