Func< T>回调可能导致内存泄漏

本文关键字:内存 泄漏 回调 Func | 更新日期: 2023-09-27 18:06:54

每个人都知道永远不会从invocationList中删除的事件处理程序会导致c#中的内存泄漏。我的问题是,我们可以有内存泄漏,如果我们使用函数作为回调?(因此只支持一个订阅者)

以以下示例(复制并粘贴到控制台应用程序中):

class Program
{
    static void Main(string[] args)
    {
        var m = new Manager();
        var c1 = new Channel();
        m.Add(c1);
        Console.WriteLine("m = {0}",GC.GetTotalMemory(true));
        Console.ReadLine();
        m.Remove(c1);
        Console.WriteLine("m = {0}", GC.GetTotalMemory(true));
        Console.ReadLine();
    }
}
public class Manager
{
    List<Channel> channels = new List<Channel>();
    public void Add(Channel c)
    {
        channels.Add(c);
        c.OnTick = OnTick;
        c.Start();
    }
    public void Remove(Channel c)
    {
        channels.Remove(c);
        //do we have a memory leak at this point?
        //does c1 still pointing to Manager func and cannot be GCed?
        c.Stop();
    }
    private Task OnTick(int i)
    {
        Console.WriteLine(i);
        return Task.FromResult(0);
    }
}
public class Channel
{
    public Func<int, Task> OnTick;
    Random r = new Random();
    private System.Timers.Timer aTimer;
    public Channel()
    {
        OnTick = i => Task.FromResult(r.Next());
    }
    public void Start()
    {
        aTimer = new System.Timers.Timer(1000);
        aTimer.Elapsed += (sender, args) => OnTick(r.Next());
        // Have the timer fire repeated events (true is the default)
        aTimer.AutoReset = true;
        // Start the timer
        aTimer.Enabled = true;
    }
    public void Stop()
    {
        aTimer.Dispose();
    }
}

Func< T>回调可能导致内存泄漏

//此时是否存在内存泄漏?

。在ANTS Memory Profiler上测试了这个

//c1仍然指向管理器函数,不能GCed?

Manager为订阅者,Channel为发布者。如果没有对Channel实例的引用,那么它是合格的GC。