【问题标题】:Timers and Garbage Collection定时器和垃圾收集
【发布时间】:2015-11-26 03:15:40
【问题描述】:

假设我有这样的课程

class A
{
    private B _objB
    private Timer _timer; // Using System.Timers 

    public A(objB)
    {
        _objB = objB;
        _timer = new Timer();
        _timer.Interval = 1000;
        _timer.Elapsed += SomeEvent;
    }

    public void Begin()
    {
        _timer.start();
    }

    public void End()
    {
        _timer.Dispose();
    }

    public void SomeEvent (object sender, ElapsedEventArgs e)
    {
        if (_objB.Condition())
        {
            // do something
        }
        else 
        {
            _timer.Dispose();
        }
    }
}

现在我在另一个类的代码中的其他地方执行此操作

public void SomeMethod(B objectB)
{
    A objA = new A(objectB);
    objA.Begin();
   // do other stuff
   // objA.End() can be called here but for this example it's not
}

我知道当我退出 SomeMethod() 的作用域时,objA 将不会被垃圾回收,因为有一个计时器事件不断触发。我不确定的是:

1) 在 SomeEvent 中,我点击 else 条件并调用 _timer.Dispose(),这会停止触发更多事件,但这会告诉 GC 它可以清理计时器和 objA 吗?换句话说,我是否造成了任何内存泄漏?

2) 是否有任何可能导致异常的竞争条件?因此,如果我正在调用 _timer.Dispose() 并且以某种方式在队列中有另一个计时器事件,那么输入该事件会导致任何异常吗?

我只是不确定我是否进行了适量的清理以避免内存泄漏。

【问题讨论】:

    标签: c# memory-management memory-leaks timer garbage-collection


    【解决方案1】:
    1. 通常是正确的。当您处置 Timer 时,ObjA 将有资格获得 GC。事实上,垃圾收集器会在下一个垃圾收集周期中收集它。

    请记住,它不会在您的对象符合 GC 条件后立即收集它。垃圾收集器使用其启发式算法来触发垃圾收集。它仅在存在内存压力时发生。实际上当 Gen0 或大对象堆即将溢出时。

    1. 可能……看看here

    回调可以在 Dispose() 方法重载之后发生 调用,因为计时器将回调排队等待线程执行 池线程。您可以使用 Dispose(WaitHandle) 方法重载来 等待所有回调完成。

    【讨论】:

    • 哦,好吧,只要它最终得到垃圾收集,我就可以了。至于链接,我正在使用 System.Timers 所以我不相信我可以访问其他 Dispose() 方法。我想我的问题是如果我已经调用了 timer.Dispose(),并且我在队列中有一个事件,实际上有什么危害吗?
    • @tmk1108:显然是正确的。在你丢弃它之前停止你的计时器。
    猜你喜欢
    • 2015-01-06
    • 1970-01-01
    • 2012-06-28
    • 2015-03-14
    • 2018-12-30
    • 1970-01-01
    • 2011-01-06
    • 2015-07-10
    • 2010-12-23
    相关资源
    最近更新 更多