这是内存泄漏还是垃圾收集会修复它
假设我有一个被单击的按钮,它会执行以下操作:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
如果此按钮被单击 100 次,那些已创建的实例会发生什么?垃圾收集是否会启动,或者是否需要调用 System.Timers.Timer.Close 方法?如果需要,您从哪里调用它?
Lets say I have a button that gets clicked and it does this:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
If this button gets clicked 100 times what happens to those instances that have been created? Will garbage collection kick in or does the System.Timers.Timer.Close
method need calling and if it does where do you call it from?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不,这不会导致内存泄漏。事实上,您的代码的编写方式并不能保证正确执行。
Timers.Timer
实际上只是Threading.Timer
的包装器,并且它被明确列为可收集,即使它当前正在运行。在这里,您没有保留对它的引用,因此下一个 GC 可以在您的表单仍在运行时且在事件触发之前收集它
EDIT
Timers.Timer
的文档出现是不正确的。如果未引用Timer
实例,则不会收集它。它确实会继续存在No this will not cause a memory leak. In fact the way your code is written it's not guaranteed to execute properly.
Timers.Timer
is really just a wrapper overThreading.Timer
and it's explicitly listed as being collectable even if it's currently running.Here you keep no reference to it and hence the very next GC could collect it while your form is still running and before the event ever fires
EDIT
The documentation for
Timers.Timer
appears to be incorrect. TheTimer
instance will not be collected if it's unreferenced. It will indeed live on一旦方法离开,它们将被收集。
TimerElapsed
是否被调用取决于Timer
何时最终确定。很有可能不到一秒就死掉了。当您调用
Timer.Close()
时,您会调用Timer.Dispose()
从计时器队列中取消注册计时器,在这种情况下,不会调用 TimerElapsed (当然,如果之前没有调用过的话)。如果您未关闭计时器,GC 最终将调用
Finalize()
,而后者又会调用Dispose()
。但没有确切的信息什么时候会发生:)请参阅下面的示例,
Console.Out.WriteLine("used!!!")
永远不会执行:They will be collected once method is left.
TimerElapsed
will be either called or not depending on whenTimer
gets finalized. Most likely it will be dead long before 1 second passed.When you call
Timer.Close()
you thus callTimer.Dispose()
that de-registers timer from timer queue and in that case TimerElapsed won't be called (of course if it was not called before).If you leave timer not closed, GC will eventaully call
Finalize()
that in turn will callDispose()
. But there is not exact knowledge when it will happen :)See below example,
Console.Out.WriteLine("called!!!")
will never execute:在 the_joric 和 JaredPar 的回答以及运行探查器测试之后,显示计时器在垃圾收集启动后仍然存在,其原因是因为存在对事件处理程序的引用。有关更详细的说明,请参阅 这个答案。
真正的答案是,除非在已用事件处理程序中关闭计时器,否则这是内存泄漏。
只是为了表明,尽管我相信伟大贡献者对 SO 的回答(也许太多了),但他们可能略有偏差。
After answers by the_joric and JaredPar and running profiler tests which showed timers sticking around after garbage collection kicked in the reason they stuck around was because there is a reference to the event handler sticking around. For a more detailed explanation see this answer.
The real answer is that it is a memory leak unless the timer is closed in the elapsed event handler.
Just goes to show that although I trust the answers on SO (maybe too much) from the great contributors they may be slightly off.