Till today I was thinking that members of reachable objects are also considered to be reachable.
But, today I found one behavior which creates a problem for us either when Optimize Code
is checked or application is executed in Release Mode. It is clear that, release mode comes down to the code optimization as well. So, it seems code optimization is reason for this behavior.
Let's take a look to that code:
public class Demo
{
public Action myDelWithMethod = null;
public Demo()
{
myDelWithMethod = new Action(Method);
// ... Pass it to unmanaged library, which will save that delegate and execute during some lifetime
// Check whether object is alive or not after GC
var reference = new WeakReference(myDelWithMethod, false);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
Console.WriteLine(reference.IsAlive);
// end - Check whether object is alive or not after GC
}
private void Method() { }
}
I simplified code a bit. Actually, we are using our special delegate, not Action
. But the behavior is same. This code is written in mind with "members of reachable objects are also considered to be reachable". But, that delegate will be collected by GC asap. And we have to pass it to some unmanaged library, which will use it for some time.
You can test demo by just adding that line to the Main
method:
var p = new Demo();
I can understand the reason of that optimization, but what is the recommended way to prevent such case without creating another function which will use that variable myDelWithMethod
which will be called from some place? One, option I found that, it will work if I will set myDelWithMethod
in the constructor like so:
myDelWithMethod = () => { };
Then, it won't be collected until owning instance is collected. It seems it can't optimize code in the same way, if lambda expression is setted as a value.
So, will be happy to hear your thoughts. Here are my questions:
Is it right that, members of reachable objects are also considered to be reachable?
Why it is not collected in case of lambda expression?
Any recommended ways to prevent collection in such cases?