FileSystemWatcher memory leak even after launching Finalizer

Registering for an event FileSystemWatcher

does not force the registration class to stay in memory even after all (my) references to FileSystemWatcher

and allowed to run GC and finalizers. I have provided an example below, showing how the using object FileSystemWatcher

stays in memory and another set of objects (such as A

and B

) that use similar events / event handlers 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 what FileSystemWatcher implements IDisposable

    and what I should be calling Dispose()

    when I'm done with it. But I understand that if I miss the call Dispose()

    , it simply means that the work it needed to do will be done later during the finalizer.

  • There is a known FileSystemWatcher memory leak documented here . But the description is different from what I am describing.

  • I used Red Hat ANTS Memory Profiler to show that it supports it: Image showing what is keeping UsesFileWatcher object alive

Question:

Is this an error in FileSystemWatcher

, or my expectations incorrect?

+3


source to share


1 answer


Of course, this is not a mistake. You can directly see in the profiler that the object is being referenced. There's a system type that has a root code that has a callback that it has in FSW making it accessible from the root object.



It will remove those callbacks when it is removed, allowing it to be collected, so you will need to dispose of it if you want it to be eligible for collection.

-1


source







All Articles