2009-08-22 14 views
6

C#で多くのイテレータを使用した場合のメモリ使用量への影響は?何千ものforeachループを実行するプログラムを仮定しましょう - 各ループはGetEnumeratorの呼び出しによってヒープ上に一時オブジェクトを割り当てますか? CLRはあらゆる種類の最適化を実行しますか(例えば、IEnumeratorオブジェクトのスタック割り当て)?それとも、これは単に心配するほど重要な問題ではありませんか?C#でのイテレータのメモリ使用量

答えて

13

ほとんどの場合、それほど心配するほど重要ではありません。エリックが指摘しているように、ケースが重要なケースがあるかもしれませんが、私の経験ではかなり少なくて済みます。

foreachループを何十万行している場合は、おそらく実際にはの作業をループ内で実行しているとします。それはほぼ確実にfarであり、イテレータ自身よりも重要です。

foreachを配列(コンパイル時には配列であることがわかっています)に使用すると、とにかくIEnumerable<T>は使用されません。直接インデックスを使用します。私はこれに基づいて私のコードを変更しません。

これまでのように、パフォーマンスを心配している場合は、パフォーマンスを測定してプロファイルする必要があります。ボトルネックは、あなたが期待する場所ではほとんどありません。

+13

これは、いつものように優れたアドバイスJonですが、私たちのパフォーマンステストは、現実のシナリオではヒープ割り当て/イテレータのガーベジコレクションによって大きなパフォーマンスの影響を受けています。だからList の列挙子は参照型ではなく悪い可変値型です。しかしもちろん、そこには「私たちのパフォーマンステスト」というキーワードがあります。データなしでパフォーマンスを判断するのは愚かです。 –

+2

ああ、邪悪な変更可能な 'List 'イテレータ - 私は妥当なコードのように見えるニュースグループの投稿を覚えているようですが、そのデザインの決定のために非常に奇妙な結果が出ました:)答えを編集しますとにかく... "それは重要ではない"という包括的主張はめったに良い考えではない。 –

2

多くの場合、コンパイラはforeachループを単純なループに最適化することができます。このループは、スタック(またはプロセッサレジスタ)にインデックス変数のみを必要とします。

イテレータがまだ使用されている場合、それらのほとんどは構造体なので、ヒープ上ではなくスタック上に割り当てられます。

クラスである少数の反復子は、依然として非常に小さく高速です。あなたは目に見えないほどの影響を与えずに何百万というものを作り出すことができます。

+0

すばらしい音...素早いフォローアップの質問:IEnumerableインターフェイスを実装すると、定義によってGetEnumeratorメソッドがIEnumeratorを返します。私のカスタムイテレータが構造体の場合、私はそれがボックスオブジェクトとして返されると仮定していますか? –

+6

Jen、_carefully_リストがそれをする方法を見てください、あなたはボクシングを回避する方法を見ます。そのトリックは、* "foreach"ループは実際にIEnumerator *を返すためにGetEnumeratorを必要としないということです。適切なプロパティとメソッドを持つものを返す限り、あなたは金色です。これにより、構造体を返すパブリックGetEnumeratorとボックス化された構造体を返す明示的IEnumerable .GetEnumeratorを持つことで、ボクシングを回避できます。 –

+4

しかし、ヒープ上に列挙子を作成することが、実際の、顧客に影響を与えるパフォーマンス上の問題の大きな原因であるという確かなデータがない限り、このようなことはやめてください。変更可能な値の型は、デバッグするのに費用がかかり、理解しづらいあらゆる種類の奇妙な問題を引き起こします。 –