事件如何导致 C# 中的内存泄漏以及弱引用如何帮助缓解这种情况? [英] How do events cause memory leaks in C# and how do Weak References help mitigate that?

查看:16
本文介绍了事件如何导致 C# 中的内存泄漏以及弱引用如何帮助缓解这种情况?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有两种方法(据我所知)在 C# 中导致意外内存泄漏:

There are two ways (that I know of) to cause an unintentional memory leak in C#:

  1. 不处理实现IDisposable
  2. 的资源
  3. 错误地引用和取消引用事件.

我不太明白第二点.如果源对象的生命周期比侦听器长,并且当没有其他引用时侦听器不再需要事件,则使用普通 .NET 事件会导致内存泄漏:源对象将侦听器对象保存在内存中应该被垃圾收集.

I don't really understand the second point. If the source object has a longer lifetime than the listener, and the listener doesn't need the events anymore when there are no other references to it, using normal .NET events causes a memory leak: the source object holds listener objects in memory that should be garbage collected.

你能解释一下事件如何使用 C# 中的代码导致内存泄漏,以及我如何使用弱引用和不使用弱引用来解决它?

Can you explain how events can cause memory leaks with code in C#, and how I can code to get around it using Weak References and without Weak References?

推荐答案

当侦听器将事件侦听器附加到事件时,源对象将获得对侦听器对象的引用.这意味着在分离事件处理程序或收集源对象之前,垃圾收集器无法收集侦听器.

When a listener attaches an event listener to an event, the source object will get a reference to the listener object. This means that the listener cannot be collected by the garbage collector until either the event handler is detached, or the source object is collected.

考虑以下类:

class Source
{
    public event EventHandler SomeEvent;
}

class Listener
{
    public Listener(Source source)
    {
        // attach an event listner; this adds a reference to the
        // source_SomeEvent method in this instance to the invocation list
        // of SomeEvent in source
        source.SomeEvent += new EventHandler(source_SomeEvent);
    }

    void source_SomeEvent(object sender, EventArgs e)
    {
        // whatever
    }
}

...然后是以下代码:

...and then the following code:

Source newSource = new Source();
Listener listener = new Listener(newSource);
listener = null;

即使我们将 null 分配给 listener,它也不符合垃圾回收的条件,因为 newSource 仍然持有对事件处理程序 (Listener.source_SomeEvent).要修复这种泄漏,重要的是在不再需要时始终分离事件侦听器.

Even though we assign null to listener, it will not be eligible for garbage collection, since newSource is still holding a reference to the event handler (Listener.source_SomeEvent). To fix this kind of leak, it is important to always detach event listeners when they are no longer needed.

写上面的样例,主要是针对泄漏的问题.为了修复该代码,最简单的方法可能是让 Listener 保留对 Source 的引用,以便稍后分离事件侦听器:

The above sample is written to focus on the problem with the leak. In order to fix that code, the easiest will perhaps be to let Listener hold on to a reference to Source, so that it can later detach the event listener:

class Listener
{
    private Source _source;
    public Listener(Source source)
    {
        _source = source;
        // attach an event listner; this adds a reference to the
        // source_SomeEvent method in this instance to the invocation list
        // of SomeEvent in source
        _source.SomeEvent += source_SomeEvent;
    }

    void source_SomeEvent(object sender, EventArgs e)
    {
        // whatever
    }

    public void Close()
    {
        if (_source != null)
        {
            // detach event handler
            _source.SomeEvent -= source_SomeEvent;
            _source = null;
        }
    }
}

然后调用代码可以发出信号表明它已使用对象完成,这将删除Source对Listener"的引用;

Then the calling code can signal that it is done using the object, which will remove the reference that Source has to ´Listener`;

Source newSource = new Source();
Listener listener = new Listener(newSource);
// use listener
listener.Close();
listener = null;

这篇关于事件如何导致 C# 中的内存泄漏以及弱引用如何帮助缓解这种情况?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆