即使在Finalizer运行后,FileSystemWatcher内存也会泄漏

时间:2014-10-23 20:27:19

标签: c# memory-leaks

注册FileSystemWatcher上的事件会导致注册类在取消FileSystemWatcher的所有(我的)引用并让GC和终结器运行后保留在内存中。我在下面构建了一个示例,展示了使用FileSystemWatcher的对象如何保留在内存中,而使用类似事件/事件处理程序的另一组对象(类型AB)则没有留在记忆中。

示例

class Program
{
    class UsesFileWatcher
    {
        public FileSystemWatcher fw;

        public UsesFileWatcher()
        {
            fw = new FileSystemWatcher(@"C:\", "*.txt");
            fw.Changed += eventHandler;
            fw.EnableRaisingEvents = true;
        }

        void eventHandler(object sender, FileSystemEventArgs e)
        {
        }
    }

    // For Comparison, I have classes A and B which use similar events and event handlers
    class A
    {
        public event EventHandler AEvent;
    }

    class B
    {
        public A a;

        public B()
        {
            a = new A();
            a.AEvent += eventHandler;
        }

        void eventHandler(object sender, EventArgs e)
        {
        }
    }

    static void Main(string[] args)
    {
        var weakRefToB = WeakReferenceToB();
        var weakRefToUsesFileWatcher = WeakReferenceToUsesFileWatcher();

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("B Alive = {0}", weakRefToB.IsAlive);
        Console.WriteLine("UsesFileWatcher Alive = {0}", weakRefToUsesFileWatcher.IsAlive);

        Console.ReadKey();
    }

    static WeakReference WeakReferenceToB()
    {
        return new WeakReference(new B());
    }

    static WeakReference WeakReferenceToUsesFileWatcher()
    {
        return new WeakReference(new UsesFileWatcher());
    }
}

备注:

  • 我知道FileSystemWatcher实现了IDisposable,并且当我完成它时我应该调用Dispose()。但我的理解是,如果我错过了对Dispose()的调用,那就意味着它需要做的工作将在终结期间完成。

  • 记录了here已知的FileSystemWatcher内存泄漏。但这种描述听起来与我所描述的不同。

  • 我使用Red Gate的ANTS Memory Profiler来显示保持活着的原因: Image showing what is keeping UsesFileWatcher object alive

问题:

这是FileSystemWatcher中的错误还是我的期望不正确?

1 个答案:

答案 0 :(得分:-1)

当然,这不是一个错误。您可以在分析器中看到正在引用该对象。有一个根系的系统类型,它有一个FSW回调,使其可以从一个有根的对象访问。

它将在处理时删除这些回调,使其能够被收集,因此如果您希望它有资格收集,您将需要处置它。