gpt4 book ai didi

c# - 垃圾收集和 GCHandle.Alloc

转载 作者:行者123 更新时间:2023-12-02 22:15:06 25 4
gpt4 key购买 nike

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 类要求 GC 不使用 - GCHandle.Alloc 进行收集。伙计们,这是内存泄漏的一大来源。除非我设置 t.Enabled = false,否则即使我们关闭表单,整个表单也会泄露。

在第一个示例代码中,我不明白为什么即使在我触发了 GC.Collect() 之后表单也没有被垃圾回收。在反射器中,我看到在内部使用 GCHandle.Alloc 的 Form 中使用了 ControlNativeWindow。这是一个原因吗?作为 .NET 库的用户,我始终相信,当引用变得不可访问时,它将有机会进行垃圾回收。当然,垃圾收集和内存的实际释放是不确定的。但我的问题是——我对这两个例子的理解是否正确?如果有些对象即使在无法访问后仍然可以存活,那么我将如何跟踪它以防止内存泄漏?

最佳答案

Winforms 保留一个内部表,将句柄映射到控制实例。该表确保只要 native 窗口处于事件状态,控件(您的情况下的表单)就永远不会被垃圾收集。当窗口被销毁时,它会从该表中删除,无论是通过用户关闭表单还是您的代码处理它。

System.Timers.Timer 由 CLR 引用的 cookie 保持事件状态。该类是使用 System.Threading.Timer 实现的,它具有一个采用state 对象参数的构造函数。 state 对象是 cookie,CLR 保持它与 GCHandle.Alloc() 等效项的引用。禁用计时器会重置允许计时器被垃圾收集的 cookie。

这些是框架防止这些对象过早被垃圾收集的自然而必要的方法。您只能通过在处理表单时忘记禁用计时器来导致泄漏。这通常是非常不健康的,您不希望计时器在表单死亡时继续滴答作响。将 Designer.cs 文件中的 Dispose 方法移动到表单代码中或覆盖 OnFormClosed() 以禁用计时器。

关于c# - 垃圾收集和 GCHandle.Alloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14617336/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com