.netは、使用するすべての文字列に文字列インターンを使用しますか?
いいえ。ただし、コード内の定数であるため、コンパイル時に認識している文字列には使用されます。
string x = "abc"; //interned
string y = "ab" + "c"; //interned as the same string because the
//compiler can work out that it's the same as
//y = "abc" at compile time so there's no need
//to do that concatenation at run-time. There's
//also no need for "ab" or "c" to exist in your
//compiled application at all.
string z = new StreamReader(new FileStream(@"C:\myfile.text")).ReadToEnd();
//z isn't interned because it isn't known at compile
//time. Note that @"C:\myfile.text" is interned because
//while we don't have a variable we can access it by
//it is a string in the code.
もしそうなら、それはパフォーマンスを傷つけませんか?
いいえ、パフォーマンスに役立ちます。
まず、これらの文字列はすべて、アプリケーションのメモリのどこかにあります。インターンとは、不要なコピーがないことを意味するため、使用するメモリが少なくなります。2番目:それは、私たちが知っている文字列比較を、インターンされた文字列からのものだけを超高速にします。第三に:それはあまり出てきませんが、それが他の比較に与えるブーストは出てきます。組み込みの比較プログラムの1つに存在する次のコードについて考えてみます。
public override int Compare(string x, string y)
{
if (object.ReferenceEquals(x, y))
{
return 0;
}
if (x == null)
{
return -1;
}
if (y == null)
{
return 1;
}
return this._compareInfo.Compare(x, y, this._ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
}
これは注文用ですが、同じことが等式/不等式チェックにも当てはまります。2つの文字列が等しいことを確認するか、それらを順番に並べるには、nが文字列の長さに比例するO(n)操作を実行する必要があります(スキップや巧妙さを実行できる場合でも、比例します) 。これは長い文字列の場合は潜在的に遅く、文字列の比較は多くのアプリケーションが多くの時間を行うことであり、速度を上げるのに最適な場所です。等式の場合も最も遅くなります(差を見つけた瞬間に値を返すことができますが、等しい文字列を完全に調べる必要があるため)。
「等しい」の意味を再定義しても、すべてが常にそれ自体と等しくなります(大文字と小文字を区別し、区別せず、異なるカルチャ-すべてがそれ自体と等しく、Equals()
従わないオーバーライドを作成すると、バグが発生します)。すべては常にそれが等しいものと同じポイントで注文されます。これは2つのことを意味します:
- これ以上の作業をしなくても、いつでも自分と同じものを考えることができます。
0
何かをそれ自体と比較するための比較値は、これ以上の作業なしでいつでも与えることができます。
したがって、上記のコードは、より複雑で費用のかかる比較を行うことなく、この場合のショートカットになります。このケースをカバーしなかった場合、いずれにせよ両方の値が合格した場合のテストを追加する必要があるため、マイナス面もありませnull
ん。
さて、何かをそれ自体と比較することは、特定のアルゴリズムが機能する方法で非常に頻繁に自然に起こるので、それは常に行う価値があります。ただし、文字列のインターンは、値が異なる2つの文字列(たとえばx
、z
質問の先頭)が実際に同じである時間を増やすため、ショートカットが機能する頻度が高くなります。
ほとんどの場合、これは小さな最適化ですが、無料で入手でき、頻繁に入手できるので、入手するのは素晴らしいことです。これからの実用的なポイント-あなたが書いているEquals
か、Compare
あなたもこのショートカットを使うべきかどうかを検討しているなら。
関連する質問は、「私はすべてをインターンするべきですか?」です。
ただし、ここでは、コンパイルされた文字列にはない欠点を考慮する必要があります。文字列をコンパイルすると、どこかにある必要があるため、インターンが無駄になることはありません。ただし、ファイルから文字列を読み取り、それをインターンし、それを二度と使用しない場合、それは長持ちすることになり、それは無駄です。あなたがいつもそれをしたならば、あなたはあなたの記憶の使用を損なう可能性があります。
あなたがいくつかの識別子を含むたくさんのアイテムを頻繁に読んでいると想像してみましょう。これらの識別子を定期的に使用して、アイテムを別のソースからのデータと照合しています。これまでに表示される識別子の小さなセットがあります(たとえば、可能な値は数百個しかない)。次に、等価性チェックがこれらの文字列のすべてであり、それらが多くないため、インターン(読み込まれたデータと比較するデータの両方で-それ以外の場合は無意味です)が優先されます。
または、そのようなオブジェクトが数千あり、一致するデータが常にメモリにキャッシュされているとしましょう。つまり、これらの文字列は常にメモリ内のどこかにあるため、インターンは簡単に勝ちます。(多くの「見つからない」結果の可能性がない限り、一致するものが見つからないためにそれらの識別子をインターンすることは損失です)。
最後に、同じ基本的な手法を別の方法で実行できます。XmlReader
たとえば、比較対象の文字列をNameTable
プライベートインターンプールのように機能する文字列に格納しますが、終了時にすべてを収集できます。この手法は、プールされている間は変更されない任意の参照型に適用することもできます(これを不変にして、いつでも変更されないようにするのが最善の方法です)。大量の重複を伴う非常に大規模なコレクションでこの手法を使用すると、メモリ使用量を大幅に削減できます(私の最大の節約は少なくとも16GBでした-それ以上になる可能性がありますが、手法が適用される前のその時点でサーバーがクラッシュし続けました)および/または速度比較アップ。