![]() ![]() ![]() |
![]() |
||||||||||||||||
![]() |
||||||||||||||||
毎回コラムという形で、本編で紹介できなかった内容をご紹介してゆきたいと思います。 最初のコラムでは、パフォーマンスに関して取り上げます。 .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クラスの文字列連結の比較
|
||||||||||||||||
前へ | ページトップへ | 次へ![]() |