Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 这是内存泄漏还是垃圾收集会修复它_C#_.net_Performance_Memory Leaks_Garbage Collection - Fatal编程技术网

C# 这是内存泄漏还是垃圾收集会修复它

C# 这是内存泄漏还是垃圾收集会修复它,c#,.net,performance,memory-leaks,garbage-collection,C#,.net,Performance,Memory Leaks,Garbage Collection,假设我有一个被点击的按钮,它是这样做的: 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 = 10

假设我有一个被点击的按钮,它是这样做的:

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
方法?如果需要,从何处调用它?

方法离开后,它们将被收集
TimeRecursed
将被调用或不调用,具体取决于
Timer
何时完成。最有可能的是,它将在1秒过去之前很久死去

当您调用
Timer.Close()
时,您将调用从计时器队列中注销计时器的
Timer.Dispose()
,在这种情况下,不会调用timerecursed(当然,如果以前没有调用它)

如果您保持计时器未关闭,GC最终将调用
Finalize()
,然后调用
Dispose()
。但目前还不清楚何时会发生:)

请参见下面的示例,
Console.Out.WriteLine(“调用!!!”)
将永远不会执行:

using (System.Timers.Timer NewTimer = new System.Timers.Timer())
{
    NewTimer.AutoReset = false;
    ElapsedEventHandler TimerElapsed = (sender, args) => { Console.Out.WriteLine("called!!!"); };
    NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
    NewTimer.Interval = 1000;
    NewTimer.Start();
}

Thread.Sleep(3000);

不,这不会导致内存泄漏。事实上,您编写代码的方式不能保证正确执行
Timers.Timer
实际上只是
Threading.Timer
上的一个包装器,它被明确列为可收集的,即使它当前正在运行

http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
在这里,您不保留对它的引用,因此下一个GC可以在您的表单仍在运行并且在事件触发之前收集它

编辑

Timer.Timer
的文档似乎不正确。如果未引用
计时器
实例,则不会收集该实例。它确实将继续存在下去

var timer = new System.Timers.Timer
{
    Interval = 400,
    AutoReset = true
};
timer.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer.Enabled = true;

WeakReference weakTimer = new WeakReference(timer);
timer = null;

for (int i = 0; i < 100; i++)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

Console.WriteLine("Weak Reference: {0}", weakTimer.Target);
Console.ReadKey();
var timer=new System.Timers.timer
{
间隔=400,
自动重置=真
};
timer.appead+=(u,uu)=>Console.WriteLine(“Stayin alive(2)…”);
timer.Enabled=true;
WeakReference weakTimer=新的WeakReference(计时器);
定时器=空;
对于(int i=0;i<100;i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
WriteLine(“弱引用:{0}”,weakTimer.Target);
Console.ReadKey();

在joric和JaredPar的回答和运行探查器测试之后,这些测试显示计时器在垃圾收集启动后仍然存在,原因是存在对事件处理程序的引用。有关更详细的解释,请参阅答案

真正的答案是这是内存泄漏,除非计时器在经过的事件处理程序中关闭


这表明,尽管我相信来自伟大贡献者的答案(可能太多了),但他们可能会有点不信任。

或者一旦触发了经过的事件,您可以对经过的事件调用Close吗?当然可以,但如果timer仍然是一个方法变量,则可能永远不会触发经过的事件:)。您需要将其设置为类变量(字段)。在经过的事件中,您不能只调用((计时器)发送器)。关闭()可以:),但经过的事件代码不会在您的示例中执行(至少在99%的情况下)。调用Close()也没有多大意义,因为您已将AutoReset设置为false,这意味着该事件将只执行一次。我的形式不只是用于演示目的。想象一下,它是一个类中的方法调用,可能会被频繁解雇。我什么时候关闭它呢?只是做了一些测试,并在GC启动计时器时使用了Redgate Antzmemory@Jon然后,要么它们已经被提升到第2代,并且它是一个仅限第1代的GC,要么它们在其他地方被引用。如果它们没有被引用,那么它们肯定是可收集的。@JaredPar或它们正在等待终结器运行--可终结对象需要2个GC。@Jon它们是可终结的,所以它们需要等待终结器运行。