2016-10-19 5 views
3

私は疑問に思いました。次のコードスニペットは、2番目のコードより多くのメモリを消費しますか?匿名関数はループでより多くのメモリを取るdo

List<Action> myList = new List<Action>(); 
for(int i = 0; i < 10000; i++) 
{ 
    myList.Add(() => { /* Code */}); 
} 

今回は、方法を指しています。

List<Action> myList = new List<Action>(); 
for (int i = 0; i < 10000; i++) 
{ 
    myList.Add(myFuntion); 
} 

void myFuntion()... 

それは匿名メソッドを保存する必要があるため、最初のコードスニペットは、より多くのメモリを使用する場合、私は思っていました。それとも、同じ匿名関数に毎回

を指していると関数に2番目のコードスニペットのポイントをしたり、それが

おかげ

+0

一般にコンパイラはラムダの代理人を生成します - 実行時には通常の方法と変わりませんが、ここではいくつかの例外があります。 –

+0

Analyze> Performance Profiler> Tick Memory Usage> Start> Take snapshot> end programに移動し、結果を確認します。でもクロージャの場合には、コンパイラが閉じられた変数のためのメンバーを含む(と彼らはあなたのために更新され続ける)クラスを生成 –

答えて

2

たびは、私が言うことはできません全体の機能を格納しません。 NETは確かですが、一般的には、無名関数が降伏関数から要素を取得するかどうかによって異なります(例:myList)。そうでない場合は、コンパイラによって生成された名前を持つ通常の静的関数に変更できます。

もし何かをキャプチャすると、コンパイラはキャプチャされた変数を格納する余分なデータ構造を生成して割り当てなければなりません。これをコンパイラ生成関数の引数として使用します。例えば。あなたがmyList.Add(() => { var z = myList.Count; .... });を行う場合、コンパイラはそれのためにこのようなものを生成する必要があります。

class GenertedEnv 
{ 
    public List<Action> myList; 
} 

static void AnonymousFunction(GeneratedEnv env, /* Plus other lambda parameters*/) 
{ 
    var z = env.myList.Count; 
    ... 
} 
+0

- (http://tryroslyn.azurewebsites.net/#K4Zwlgdg5gBAygTxAFwKYFsB0AZSBHAbgChRJZEUNMBhAewBt7UBjZMWiETAcVQlQBOYZsVLR4SNOmJEADsABG9YTGb0AhiBAwAYrVowA3kSIwzMeUpUp1bZjAButMABMYAWXWQAFAEojRACQgbgoADwAgqzsEAB8MOgIocgwALww/ADuMMmR0RyxfsTBAGa0At6QKWBpMAAMBDA1YTAAjHUdDU0A1N2+QYHG5sGBicmYES4u3n5p8YYwdJwMqJgA6kJouPzeAEQAcsDoCoIwuzDdTb4EAL7XAzdBjzdAA [こちら]を参照==)。 「ランタイムメソッド生成」は必要ありません。 –

+0

A [良好例](http://tryroslyn.azurewebsites.net/#K4Zwlgdg5gBAygTxAFwKYFsB0AZSBHAbgChRJZEUNMBhAewBt7UBjZMWiETAcVQlQBOYZsVLR4SNOmJEADsABG9YTGb0AhiBAwAYrVowA3kSIwzMeUpUp1bZjAButMABMYAWXWQAFAEojRACQgbgoADwAgqzsEAB8MOgIocgwALww/ADuMMmR0RyxfsTBAGa0At6QKWBpMAAMBDA1YTAAjHUdDU0A1N2+QYHG5sMjDuoCMAAetWDE5sGBicmYES4u3n5p8YYwdJwMqJgA6kJouPzeAEQAcsDoCoIwlzDdU74EAL7vpiO/P7/DSa9YqBD5BMEfIA=)変数の値が変更されたときにクラスメンバーが更新される方法を示しています。 –

+0

ここでは、コンパイラが実行時に生成されるのではなく、クラスと関数を生成すると言っています。しかし、はい、あなたのリンクから逆コンパイルされたコードは、コンパイラが実際に何をしているのかを視覚化するのに役立ちます。 – Matthias247

2

第一の方法は、メソッドと内部クラスを作成し、リストに追加しているActionデリゲートにそのメソッドを割り当てます。
ただし、アクションをインスタンス化して毎回リストに追加するだけです。
出典:tryroslyn

第二の方法は、それがすべてのループで新しいアクションをインスタンス化します

list.Add(new Action(MyFunction)); 

に相当します。

あなたはそれをテストし、第一の方法は、1つのアクションだけインスタンス化します見ることができます:それは舞台裏で何が起こっているかを発見するために、時には非常に驚くべきことができ
dotnetfiddle
を。

+0

したがって、2番目の方法は遅いですか? –

+0

また、tryroslynリンクが動作していません。 –

+1

@ CodeJoyそうだね。私はそれもこれをしたのか分からなかった。両方の方法が本質的に同じであると私は期待した。 (tryroslynリンクをコピーすると何かが間違っていましたが、すべてのブラウザで動作しないことが判明しました) –