C#+WPFチューニング戦記

C#とWPFで高速なコードと最適なシステムを書くためにやってきたいろいろな事を書いてみます。.NET Frameworkのソースコードを読み解きましょう。なお、ここに書かれているのは個人の見解であって何らかの団体や企業の見解を代表するものではありません。

85000バイト問題はいまだ健在

ガーベージコレクション(GC)のジェネレーションのことを調べたことはあるでしょうか。

.NET FrameworkGCは現在3つのジェネレーションがあります。

  • 極めて短期的なオブジェクトを扱うジェネレーション0
  • ある程度の期間に渡って保持されたオブジェクトのジェネレーション1
  • 長期的に参照を保持されたものが到達するジェネレーション2

というわけですが、ジェネレーション0と1に関するGCの処理は実に実に高速です。

対してジェネレーション2に入り込んでしまったオブジェクトは、GCによって処理されるのにかなりの処理時間を要します*1

問題はたったの1つ。85000バイトを超えるオブジェクトは、作られた当初からジェネレーション2に配置されます。なので、一時オブジェクトには本当に向いていません。大体は配列などのコレクションということになるでしょう。

ですから、生成されて即時廃棄されるオブジェクトのために、大きなテーブルを作ってはいけません。GCの稼働時になかなかのパフォーマンス劣化を生み出します。

対策はざっくりと以下のようになります。

  • 大きなオブジェクトや配列自体は再利用可能なマネージメントを行う
  • 大きなオブジェクトはアンマネージ領域に配置する
  • 大きなオブジェクトを作らないためにLinkedListやSortedDictionaryを使用する
    (ただし、速度面のコストは十分理解してください)
  • 頻度が高くなければGCに委ねることももちろん手段の1つ

とはいえ、実際にはオブジェクトで85000バイトなんてあっという間に使ってしまうものです。画像とかを扱えばこの10倍は大きいものなど頻繁に扱うこととなります。

すべてのオブジェクトに対してうまい対処はなかなかできないと思います。なので、この辺りは今後も長く続く課題、ということになるでしょう。

*1:もともと長期保持を目的としたオブジェクトなら別に問題ありません