1

我有一个 Timer 函数,我从global.asax 中的 Application_Start调用它

这是课程:

public class AlertTimer
{
    public AlertTimer()
    {
        //
        // TODO: Add constructor logic here
        //
    }
    static System.Timers.Timer aTimer = new System.Timers.Timer();
    public static void Start()
    {
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        aTimer.Interval = 30000;
        aTimer.Enabled = true;
        GC.KeepAlive(aTimer);
    }
    public static void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        PresenceService ps = new PresenceService();
        ps.GetAbsenceContacts(); //takes 10 seconds
    }
}

现在,我的问题是这个类类型PresenceService ps = new PresenceService();在计时器完成运行后是否变得干净,或者 GC 将它保存在内存中并在每次 OnTimedEvent 运行时启动一个新的。

谢谢!

结论:从代码中删除 GC。天呐!

4

2 回答 2

5

现在,我的问题是如果这个类类型 PresenceService ps = new PresenceService(); 在计时器完成运行后变得干净,或者 GC 将其保存在内存中并在每次 OnTimedEvent 运行时启动一个新的。

是的。

PresenceService 的实例将离开作用域,因此会受到垃圾回收的影响。然而,由于 GC 主要是不确定的,它仍然在内存中,直到它被回收。因此,在做事并具有生命周期的对象(例如计时器)上,最好调用某种类型的“关闭”方法。

但是,我遇到的更大的问题是为什么您要在 Web 应用程序中运行计时器,以及为什么您觉得需要直接在垃圾收集器上调用任何方法。这通常表明您的应用程序有问题。

于 2013-10-03T14:15:21.827 回答
2

实例结束时将ps有资格进行垃圾收集OnTimedEvent1好吧,这当然是假设PresenceService它不会以某种方式根植它自己的引用(通过静态变量等)。

此外,GC.KeepAlive 在这种情况下也不需要。原因是它aTimer是静态的,因此它的生命周期已经与应用程序域相关联。换句话说,aTimer在方法中的任何时候都不符合收集条件,Start因为它是由静态变量半永久植根的。

GC.KeepAlive用于 GC 过于激进的场景。当您使用发布配置编译应用程序并在调试器之外运行它时,GC 将标记对象实例符合收集条件,甚至在它们超出范围之前。例如,ps甚至可以在GetAbsenceContracts完成之前收集!GC.KeepAlive基本上关闭了优化。您通常会在将对象引用传递给非托管 API 的非托管互操作方案中看到它。因为 GC 对非托管领域中发生的事情一无所知,它可能会错误地认为引用不再被使用并过早地收集它。


1从技术上讲,这并不完全正确。当 GC 认为它不再被使用时,该实例就有资格被收集。它实际上与它是否仍在范围内无关。

于 2013-10-03T14:26:20.627 回答