【问题标题】:FileSystemWatcher memory leak even after Finalizer has runFileSystemWatcher 内存泄漏,即使在 Finalizer 运行之后
【发布时间】:2014-10-23 20:27:19
【问题描述】:

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() 的调用,那只是意味着它需要做的工作将在终结器期间完成。

  • 有一个已知的 FileSystemWatcher 内存泄漏记录在 here。但描述听起来与我所描述的不同。

  • 我使用 Red Gate 的 ANTS Memory Profiler 来展示是什么让它保持活力:

问题:

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

【问题讨论】:

  • 好问题。我也想得到一些专业的答案。我的假设是终结器代码必须删除对事件的引用,否则它无法清理
  • 通常我使用的经验法则是,如果我使用 += 以编程方式添加处理程序,我会在使用 -= 完成时将其删除。我没有看到你在这里这样做。

标签: c# memory-leaks


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多