我有一个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。 TNX!
答案 0 :(得分:5)
现在,我的问题是这个类是否类型为PresenceService ps = new PresenceService();完成计时器运行后,它会变得干净, 或者GC将其保留在内存中并且每次都开始一个新的 OnTimedEvent运行。
是
PresenceService的实例将留下范围,因此需要进行垃圾回收。但是,由于GC大部分是不确定的,因此它一直存在于内存中,直到它被回收为止。因此,对于那些做事并有生命周期的对象(比如定时器),最好调用某种类型的“关闭”方法。
然而,我遇到的一个更大的问题是你在网络应用程序中运行计时器的原因,以及为什么你觉得需要直接在垃圾收集器上调用任何方法。这通常表明您的申请不合适。
答案 1 :(得分:2)
当ps
结束时,OnTimedEvent
实例将有资格进行垃圾收集。 1 当然,这是假设PresenceService
不以某种方式根据自己的引用(通过静态变量等)。
此外,在这种情况下不需要GC.KeepAlive
。原因是aTimer
是静态的,因此其生命周期已经与应用程序域绑定。换句话说,aTimer
无法在Start
方法中的任何一点进行收集,因为它是由静态变量半永久生根的。
GC.KeepAlive
用于GC过于激进的情况。当您使用发行版配置编译应用程序并在调试器外部运行它时,GC将标记符合收集条件的对象实例,甚至在它们超出范围之前。例如,即使在ps
完成之前,也可以收集GetAbsenceContracts
! GC.KeepAlive
基本上取消了优化。您通常会看到它在非托管互操作方案中使用,您将对象引用传递给非托管API。因为GC不知道在非托管领域发生了什么,它可能会错误地认为不再使用该引用并过早收集它。
1 从技术上讲,这不完全正确。当GC认为不再使用该实例时,该实例有资格进行收集。这与它是否仍在范围内无关。