MyCodeSucks please fix the accepted answer: kevingessner's one is wrong (as explained in the comments) and having it marked as accepted will mislead users if they don't notice Console's answer.
– AlbireoNov 13 '14 at 8:38

1

You may also see this if you define your list outside of a try/catch and do all your adding in the try/catch and then set the results to another object. Moving the defining/adding within the try/catch will allow GC. Hopefully this makes sense.
– Micah MontoyaOct 3 '17 at 16:31

I get an "Implicitly captured closure: g" warning at the first lambda. It is telling me that g cannot be garbage collected as long as the first lambda is in use.

The compiler generates a class for both lambda expressions and puts all variables in that class which are used in the lambda expressions.

So in my example g and i are held in the same class for execution of my delegates. If g is a heavy object with a lot of resources left behind, the garbage collector couldn't reclaim it, because the reference in this class is still alive as long as any of the lambda expressions is in use. So this is a potential memory leak, and that is the reason for the R# warning.

@splintor
As in C# the anonymous methods are always stored in one class per method there are two ways to avoid this:

What are possible ways to avoid this capture?
– splintorJul 3 '13 at 5:22

2

Thanks for this great answer - I've learned that there is a reason to use non-anonymous method even if it's used in just one place.
– ScottRheeOct 1 '14 at 0:51

1

@splintor Instantiate the object inside the delegate, or pass it as a parameter instead. In the case above, as far as I can tell, the desired behavior is actually to hold a reference to the Random instance, though.
– CaseyDec 18 '14 at 16:37

2

@emodendroket Correct, at this point we're talking code style and readability. A field is easier to reason about. If memory pressure or object lifetimes are important I'd chose the field, otherwise I'd leave it in the more concise closure.
– yzorgDec 30 '14 at 16:28

1

My case (heavily) simplified boiled down to a factory method that creates a Foo and a Bar. It then subscribes capturing lambas to events exposed by those two objects and, surprise surprise, the Foo keeps the captures from the Bar event's lamba alive and vice-versa. I come from C++ where this approach would have worked just fine, and was more than a little astonished to find the rules were different here. The more you know, I guess.
– dlfMar 3 '16 at 20:06

callable1 keeps a long-lived reference to its argument, helper.Lambda1

callable2 does not keep a reference to its argument, helper.Lambda2

In this situation, the reference to helper.Lambda1 also indirectly references the string in p2, and this means that the garbage collector will not be able to deallocate it. At worst it is a memory/resource leak. Alternatively it may keep object(s) alive longer than otherwise needed, which can have an impact on GC if they get promoted from gen0 to gen1.

For Linq to Sql queries, you may get this warning. The lambda's scope may outlive the method due to the fact that the query is often actualized after the method is out of scope. Depending on your situation, you may want to actualize the results (i.e. via .ToList()) within the method to allow for GC on the method's instance vars captured in the L2S lambda.

You could always figure out with a reasons of R# suggestions just by clicking on the hints like shown below:

This inspection draws your attention to the fact that more closure
values are being captured than is obviously visibly, which has an
impact on the lifetime of these values.

Consider the following code:

using System; public class Class1 {
private Action _someAction;

public void Method() {
var obj1 = new object();
var obj2 = new object();
_someAction += () => {
Console.WriteLine(obj1);
Console.WriteLine(obj2);
};
// "Implicitly captured closure: obj2"
_someAction += () => {
Console.WriteLine(obj1);
};
} } In the first closure, we see that both obj1 and obj2 are being explicitly captured; we can see this just by looking at the code. For

the second closure, we can see that obj1 is being explicitly captured,
but ReSharper is warning us that obj2 is being implicitly captured.

This is due to an implementation detail in the C# compiler. During
compilation, closures are rewritten into classes with fields that hold
the captured values, and methods that represent the closure itself.
The C# compiler will only create one such private class per method,
and if more than one closure is defined in a method, then this class
will contain multiple methods, one for each closure, and it will also
include all captured values from all closures.

If we look at the code that the compiler generates, it looks a little
like this (some names have been cleaned up to ease reading):

internal void <Method>b__0()
{
Console.WriteLine(obj1);
Console.WriteLine(obj2);
}
internal void <Method>b__1()
{
Console.WriteLine(obj1);
}
}
private Action _someAction;
public void Method()
{
// Create the display class - just one class for both closures
var dc = new Class1.<>c__DisplayClass1_0();
// Capture the closure values as fields on the display class
dc.obj1 = new object();
dc.obj2 = new object();
// Add the display class methods as closure values
_someAction += new Action(dc.<Method>b__0);
_someAction += new Action(dc.<Method>b__1);
} } When the method runs, it creates the display class, which captures all values, for all closures. So even if a value isn't used

in one of the closures, it will still be captured. This is the
"implicit" capture that ReSharper is highlighting.

The implication of this inspection is that the implicitly captured
closure value will not be garbage collected until the closure itself
is garbage collected. The lifetime of this value is now tied to the
lifetime of a closure that does not explicitly use the value. If the
closure is long lived, this might have a negative effect on your code,
especially if the captured value is very large.

Note that while this is an implementation detail of the compiler, it
is consistent across versions and implementations such as Microsoft
(pre and post Roslyn) or Mono's compiler. The implementation must work
as described in order to correctly handle multiple closures capturing
a value type. For example, if multiple closures capture an int, then
they must capture the same instance, which can only happen with a
single shared private nested class. The side effect of this is that
the lifetime of all captured values is now the maximum lifetime of any
closure that captures any of the values.