.NET ROOM.NET ROOMトップへCOMRADE総合トップへ
「1:COM/.NETコントロールの作成方法」へ

ガベージコレクションのパフォーマンスへの影響

 毎回コラムという形で、本編で紹介できなかった内容をご紹介してゆきたいと思います。
最初のコラムでは、パフォーマンスに関して取り上げます。

 .NET Frameworkでは、マネージドコード(Managed Code)で記述された部分は、
ガベージコレクション(Garbage Collection:以下GC)の管理下で動作します。
GCによって、メモリの確保/解放といったこれまでプログラマが自分で意識して
行なってきた部分を隠蔽してくれます。
非常に便利なのですが、GCによる、断片化されたメモリの回収には、
比較的パフォーマンスコストがかかってしまいます。
そのため、パフォーマンスを意識する場合には、GCを意識して(あるいは、メモリの取り方を意識して)
コーディングを行なう必要があります。

 それでは、実際にGCがパフォーマンスに影響する例として、文字列操作をみてみましょう。

 Stringクラスは非常に便利にできていて、C#でもVisual Basicのように、
文字列を足し算のように記述することができます。

   // Stringクラスによる文字列連結
   string str = "a" + "b" + "c" + "d";
   Console.WriteLine(str);
   // 結果: abcd

  しかし、だからといってループで大量に文字列を連結したり、フィルタのように大量の文字列を
比較しながら処理を組み立てるような場合には、このString.Concatをそのまま使用すると
非常に時間がかかってしまいます。
String.Concatの実装ではいったん文字列Aと文字列Bの合計数以上の領域が取られ、
そこに文字列Aと文字列Bをコピーして新しい文字列を作成しているからです(図A)。

図A:StringクラスおよびStringBuilderクラスによる文字列連結の様子


このような場合には、StringBuilderクラスを使用しましょう。
StringBuilderは、あらかじめ大きめのバッファを確保することにより、文字列処理の性能を改善できます。

 実際にこの2つの文字列連結のパフォーマンスを測定してみました。
測定に使用したコードを以下に示します。

   // String.Concat
   string str = "";
   for (int i = 0; i < 5000; i++)
    str += DateTime.Now.ToLongDateString();

   // StringBuilder
   string str = null
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < 5000; i++)
    sb.Append(DateTime.Now.ToLongDateString());
   str = sb.ToString();

  各種データの測定には、CLR Profilerというソフトを使用しました。
CLR Profilerは、CLRの開発者が、CLRのProfile APIを使用して作成した非サポートのソフトウェアで、
Microsoft社のサイトからダウンロード可能です。

 所要時間とGCの回数などは実行環境によって変わってしまいますが、
使用したメモリの量とGCの回数が極端に違っているということがわかる結果になりました(表B)。
StringBuilderの文字列連結のほうが使用するバッファが少なく、さらにはその結果として
GCの回数を抑えることになり、最終的にパフォーマンスの改善につながったと考えられます。


表B:StringクラスとStringBuilderクラスの文字列連結の比較
クラス 使用メモリ(MB) 所要時間(秒) GC回数
String.Concat 241
5.8 273
StringBuilder 2.4 2.3 5



前へ | ページトップへ | 次へ