【发布时间】:2013-01-15 01:20:21
【问题描述】:
void Foo()
{
System.Windows.Forms.Form f = new System.Windows.Forms.Form();
f.Show();
}
据我了解,f 包含对表单的引用。但是 f 是一个局部变量,当控件离开花括号时它将超出范围。但表格仍处于打开状态。我尝试调用 GC.Collect(),但表单仍然打开。
还有一个场景。
private void button2_Click(object sender, EventArgs e)
{
Timer t = new Timer();
t.Enabled = true;
t.Interval = 1000;
t.Tick += new EventHandler(t_Tick);
}
void t_Tick(object sender, EventArgs e)
{
}
在这种情况下, t 永远不会被垃圾收集。经过大量研究,我发现当我设置 t.Enabled = true 时,Timer 类使用 - GCHandle.Alloc 请求 GC 不要收集。伙计们,这是内存泄漏的一大来源。除非我设置 t.Enabled = false,否则即使我们关闭 Form,整个 Form 也会被泄露。
在第一个示例代码中,我无法理解为什么即使在触发 GC.Collect() 之后表单也没有被垃圾回收。在反射器中,我看到 ControlNativeWindow 已在内部使用 GCHandle.Alloc 的 Form 中使用。是这个原因吗。。作为 .NET 库的用户,我始终相信,当一个引用无法访问时,它就会有机会进行垃圾收集。当然,垃圾收集和从内存中的实际释放是不确定的。但我的问题是——我对这两个例子的理解是否正确?如果有对象在无法访问后仍然可以存活,那么我将如何跟踪它以防止内存泄漏?
【问题讨论】:
-
几乎没有巨大的内存泄漏.. 除非您没有让我们意识到存在巨大的生命周期/性能问题。此外,您的活动还有订阅者,不是吗?
-
当显示一个表单时,实际上可以通过
System.Windows.Forms.Application.OpenForms获取打开的表单列表。你很难说没有对表格的引用。 -
@SimonWhitehead 正如 Alvin Wong 所指出的,对于表单,可能在其他地方有引用。对于计时器示例,订阅者无法阻止垃圾回收。
-
@AlvinWong 这很有道理。
-
这让我想到了另一件事:实现
IDisposable的类拥有非托管资源,您需要显式调用Dispose来释放它们。否则,可能会发生内存泄漏。
标签: c# garbage-collection