What is the impact of C# closures on memory?

I have a class Test which holds two members, one (arr) which takes a lot of memory and the other (b) which doesn't:

public class Test
{
    public Test() {
        Arr = new int[100000000];
    }
    public bool B {get; private set;}
    public int[] Arr {get; private set;}
} 

Later in my code, I want to store a lambda expression this way:

// `test` has been declared somewhere as an instance of Test
Action lambda = () => {
    if (test.B)
        // Do things
}

What will be the memory consumption of this closure?

Will it hold the whole Test object in its environment, or only Test.b?

Should I do instead:

var tmpB = test.B;
Action lambda = () => {
    if (tmpB)
        // Do things
}
Jon Skeet
people
quotationmark

Will it hold the whole Test object in its environment, or only Test.b?

Well, it will capture the variable test (by creating a separate class to contain that variable), which in turn has a value which is a reference to the instance of Test.

In other words, a method like this:

public Action Foo()
{
    Test test = new Test();
    Action printB = () => Console.WriteLine(test.b);
    return printB;
}

will be converted into something like this:

public Action Foo()
{
    CompiledGeneratedClass tmp = new CompilerGEneratedClass();
    tmp.test = new Test();
    Action printB = tmp.GeneratedMethod;
    return printB;
}

private class CompilerGeneratedClass
{
    public Test test;

    public void GeneratedMethod()
    {
        Console.WriteLine(test.b)
    }
}

So yes, if you don't want the delegate to effectively keep the instance of Test alive, you should pull out the value of the property first. Note that that has two semantic differences though:

  • If the value of the property changes in the object, you won't see that in the delegate any more
  • If the value of test itself changes (e.g. to refer to a different instance of Test) you won't see that in the delegate any more

people

See more on this question at Stackoverflow