gpt4 book ai didi

.net - Lambda 表达式导致弱引用的目标不能成为 GC?

转载 作者:行者123 更新时间:2023-12-02 07:56:49 24 4
gpt4 key购买 nike

namespace Test
{
class Test
{
delegate void HandleMessage(string message);

public void handleMessage(string message){}

static void Main(string[] args)
{
HandleMessage listener1 = new Test().handleMessage;
WeakReference w1 = new WeakReference(listener1);

HandleMessage listener2 = (message) => { };
WeakReference w2 = new WeakReference(listener2);

Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");

listener1 = null;
listener2 = null;
GC.Collect();
Console.WriteLine("after GC");

Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");

Console.ReadLine();
}
}
}

为什么GC后w2.Target不为null?

    w1.Target:      [Test.Test+HandleMessage]    w2.Target:      [Test.Test+HandleMessage]    after GC    w1.Target:      []    w2.Target:      [Test.Test+HandleMessage]

EDIT

Thank for all the answers, Brian Rasmussen and Jon Skeet your answers are correct. Now I thoroughly understand what is going on, so I wrote another example to make everything more clearly.

The following example show that:

If Test#create() doesn't reference any instance properties or methods, then "private static HandleMessage CS$<>9__CachedAnonymousMethodDelegate1" will be created by compiler, like what Jon Skeet has said - That makes it more efficient when you use the same lambda expression multiple times.

If Test#create() does reference instance properties or methods, like the example below calling this.ToString(); then the compiler can not create a static method to replace the intstance method's logic, so after GC, the HandleMessage instance can be collected.

namespace Test
{
class Test
{
public delegate void HandleMessage(string message);

public void handleMessage(string message)
{
}

public HandleMessage create()
{
return (message) => {
//this.ToString();
};
}

static void Main(string[] args)
{
HandleMessage listener1 = new Test().handleMessage;
WeakReference w1 = new WeakReference(listener1);

HandleMessage listener2 = new Test().create();//(message) => { };
WeakReference w2 = new WeakReference(listener2);

Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");

listener1 = null;
listener2 = null;
GC.Collect();
Console.WriteLine("after GC");

Console.WriteLine("w1.Target:\t[" + w1.Target + "]");
Console.WriteLine("w2.Target:\t[" + w2.Target + "]");

Console.ReadLine();
}
}
}

最佳答案

它与 lambda 无关。对于匿名委托(delegate)可以观察到相同的行为。因此,如果您将代码更改为

HandleMessage listener2 = delegate(string message) => { };

你会得到相同的结果。

在第一种情况下,您在 Test 实例上有一个实例方法。由于当 listener1 为 null 时您没有对此实例的其他引用,因此它可能会被收集。

在第二种情况下,匿名方法必须放在某种类型上(因为方法不能单独存在)。在这种情况下,编译器将匿名方法作为静态方法放在 Test 类中。此外,引用存储在 Test 类型的静态成员中。因此 Type 也有一个对该方法的静态引用,这就是它在集合中存活的原因。

查看 IL 以了解事物的连接方式。

关于.net - Lambda 表达式导致弱引用的目标不能成为 GC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/535972/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com