可以使用lambda表达式作为事件处理程序会导致内存泄漏?(Can using lambdas as

2019-09-02 10:23发布

假设我们有以下方法:

private MyObject foo = new MyObject();

// and later in the class

public void PotentialMemoryLeaker(){
  int firedCount = 0;
  foo.AnEvent += (o,e) => { firedCount++;Console.Write(firedCount);};
  foo.MethodThatFiresAnEvent();
}

如果用这种方法类实例化和PotentialMemoryLeaker方法被调用多次,我们会泄漏内存?

有什么办法脱钩是拉姆达事件处理程序,我们就大功告成后调用MethodThatFiresAnEvent

Answer 1:

是的,它保存到一个变量并将其取下。

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); };
foo.AnEvent += evt;
foo.MethodThatFiresAnEvent();
foo.AnEvent -= evt;

是的,如果你不这样做,你会泄漏内存,因为你每次都挂钩一个新的委托对象。 您还会注意到这一点,因为每次调用此方法时,它会转储到控制台线越来越多的(不只是越来越多,但对于一个呼叫MethodThatFiresAnEvent它会转储任何数量的项目,一旦每个挂钩匿名方法)。



Answer 2:

你不会只是泄漏内存,你也将获得您的拉姆达多次调用。 “PotentialMemoryLeaker”的每个调用将拉姆达的另一个副本添加到事件列表中,当“AnEvent”被激发每一个副本将被命名。



Answer 3:

那么你可以扩展做了什么在这里 ,使与会代表使用更安全(没有内存泄漏)



Answer 4:

你举的例子只是编译成一个编译器命名的私有内部类(与现场firedCount和编译器命名的方法)。 到PotentialMemoryLeaker每次调用创建closure类到其中foo保持由委托单方法来参考的新实例。

如果不引用拥有PotentialMemoryLeaker整个对象,然后将全部在垃圾收集。 否则,您可以设置FOO为空或通过写这个空Foo的事件处理程序列表:

foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler;

当然,你需要访问的MyObject类的私有成员。



Answer 5:

是在相同的方式,正常的事件处理程序可能造成泄漏。 因为拉姆达实际上更改为:

someobject.SomeEvent += () => ...;
someobject.SomeEvent += delegate () {
    ...
};

// unhook
Action del = () => ...;
someobject.SomeEvent += del;
someobject.SomeEvent -= del;

所以基本上它只是短手,我们一直使用2.0这些年来什么。



文章来源: Can using lambdas as event handlers cause a memory leak?