Stringとメモリ
Stringは不変なオブジェクト
Stringが参照型に属しヒープメモリを使用しますがメモリの使い方が特殊です。ここではStringがどのようにメモリを使用するのかを解説していきます。 Stringクラスは不変なオブジェクトとして動作します。例えば以下のようなコードを見てみましょう。
static void Main(string[] args)
{
    Person p1 = new Person("Higty", 24);
}
これまでの参照型の動きを踏まえると以下のようにメモリを使用する予想するのではないでしょうか。
実際には以下のようにメモリを使用します。
新たに"Higch"を保存するための領域をヒープメモリに確保し Name プロパティは新たに確保した番地を指すように書き換えられます。 Stringオブジェクトは不変なので値の書き換えた場合は全て新たにヒープメモリをに領域を確保して参照先を書き換えます。 例えば以下のようなコードの場合、1行ずつにヒープメモリの確保が行われることになります。
static void Main(string[] args)
{
    String query = "SELECT * FROM MUser with(nolock) ";
    query += "WHERE Name = '" + this.textBox1.Text + "'";
    query += " AND Age <= " + this.textBox2.Text;
    query += " AND Age >= '" + this.textBox3.Text;
}
メモリの確保はそれなりにパフォーマンスに影響を与える処理です。 文字の書き換え・連結などを繰り返し行う場合は後述するStringBuilderクラスを使用するとパフォーマンスは約10倍-50倍程度アップさせることができます。 またメモリの無駄遣いを防ぐことによりガベージコレクションの回数も減らすことができます。
StringBuilderクラスとメモリ
文字を書き換え・連結をパフォーマンスを落とすことなく行うためのクラスとしてStringBuilderクラスがあります。 ここではStringBuilderクラスがどのようにメモリを使用し高いパフォーマンスを実現しているのかを解説していきます。 VisualStudioのウォッチウィンドウで.NET4.0のStringBuilderクラスの内部を見ると以下のようになっています。
内部にm_ChunkCharsというCharの配列のメンバー変数があるのがわかります。この配列の長さは16です。 以下のコードを実行してもう一度見てみます。
static void Main(string[] args)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("Higty");
}
ウォッチウィンドウで見てみると以下のようにm_ChunkCharsに値が格納されているのがわかります。
さらに以下のように16文字以上の文字を追加してみます。
static void Main(string[] args)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("Higty");
    sb.Append(" is now watching inside of StringBuilder");
}
すると内部のCharの配列の長さが増えて文字が格納されているのがわかります。
しかしよく見ると"ching inside of StringBuilder"という文字しか格納されていません。 初めの16文字はm_ChunkPreviousに格納されていることがわかります。
以下のように一度文字を追加したあとクリアして再度文字を追加した場合はどうなるでしょうか?
static void Main(string[] args)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("Higty");
    sb.Clear();
    sb.Append("Suzuki");
}
まとめると文字数がCapacityの値を超えない間は内部のm_ChunkCharsの値が書き換えられていることがわかります。 Capacityを超えると内部で新たにCharの配列が作成されているのでヒープメモリの領域の確保処理が発生していることになります。
StringBuilderクラスのCapacityプロパティは内部のCharの配列のLengthを返しています。 内部のCharの配列の長さはStringBuilderクラスのコンストラクタで指定することが可能です。
StringBuilder sb = new StringBuilder(256);
もし連結する文字の長さが事前にわかるのであれば指定したほうがよいでしょう。
Create at 2012/8/17 LastUpdate 2012/8/17