简体   繁体   中英

FileSystemWatcher memory leak even after Finalizer has run

Registering for an event on FileSystemWatcher causes the registering class to stay in memory even after eliminating all (my) references to the FileSystemWatcher and letting the GC and finalizers run. I've constructed an example below showing how an object using FileSystemWatcher stays in memory while another set of objects (of type A and B ) which use similar events/eventhandlers do not stay in memory.

Example

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());
    }
}

Notes:

  • I understand that FileSystemWatcher implements IDisposable and that I should be calling Dispose() when I'm done with it. But my understanding is that if I miss the call to Dispose() that it just means that the work it needed to do would be done later during the finalizer.

  • There is a known FileSystemWatcher memory leak documented here . But the description sounds different than what I'm describing.

  • I used Red Gate's ANTS Memory Profiler to show what is keeping it alive: 图像显示了什么使UsesFileWatcher对象保持活着状态

Question:

Is this a bug in FileSystemWatcher or are my expectations incorrect somehow?

Of course it's not a bug. You can see right in the profiler that the object is being referenced. There's a system type that is rooted that has a callback tot he FSW, making it accessible from a rooted object.

It will remove those callbacks when it is disposed of, enabling it to be collected, so you'll need to dispose it if you want it to be eligible for collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM