垃圾收集和GCHandle.Alloc [英] Garbage collection and GCHandle.Alloc

查看:748
本文介绍了垃圾收集和GCHandle.Alloc的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  void Foo()
{
System.Windows.Forms.Form f = new System.Windows.Forms.Form();
f.Show();
}

根据我的理解,f保留对Form的引用。但是f是一个局部变量,当控件离开大括号时,它将超出范围。但表格仍然是开放的。我尝试调用GC.Collect(),但表单仍然处于打开状态。



另外一个场景。

 private void button2_Click(object sender,EventArgs e)
{
Timer t = new Timer();
t.Enabled = true;
t.Interval = 1000;
t.Tick + =新的EventHandler(t_Tick);

$ b $ void t_Tick(object sender,EventArgs e)
{
$ b}

在这种情况下,t永远不会被垃圾收集。经过大量研究,我发现Timer类正在请求GC不要使用-GCHandle.Alloc来收集,当我设置t.Enabled = true时。伙计们,这是内存泄漏的一个重要来源。除非我设置t.Enabled = false,否则即使在关闭表单后,整个表单也会被泄露。

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

解决方案

Winforms保留一个映射句柄的内部表来控制实例。该表确保只要本地窗口处于活动状态,控件(您的情况下的表单)就不会被垃圾回收。当窗口被销毁时,它会从该表中删除,或者由用户关闭表单或处理它的代码。



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



这些是自然而必要的方式,框架可以防止这些对象过早地被垃圾收集。您只能在表单处理时忘记禁用计时器而导致泄漏。通常情况下,这是非常不健康的,你不希望计时器在表格死机时保持滴答状态。将Dispose方法从Designer.cs文件移入表单代码或重写OnFormClosed()以禁用计时器。


void Foo()
{
     System.Windows.Forms.Form f = new System.Windows.Forms.Form();
     f.Show();
}

To my understanding f holds the reference to the Form. But f is a local variable and it will go out of scope when the control leaves the curly braces. But the Form is still open. I tried calling GC.Collect(), but the Form is still open.

One more scenario.

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)
    {

    }

In this scenario the t is never getting garbage collected. After a lot of research, I found Timer class is requesting GC not to collect using - GCHandle.Alloc when I set t.Enabled = true. Guys, this is a big source of memory leak. Unless I set t.Enabled = false, the whole Form will be leaked even after we close the Form.

In the first example code, I could not understand why the Form didn't get garbage collected even after I trigger a GC.Collect(). In reflector I saw ControlNativeWindow has been used in Form which internally uses GCHandle.Alloc. Is that a reason?. As a user of the .NET library, I always believed that when a reference goes not reachable, it will get a chance for garbage collection. Of-course garbage collection and the actual release from memory is un-deterministic. But my question here is - Is my understanding correct for both the examples? When there are objects that can live even after it goes not-reachable, then how will I track that to prevent memory leak?

解决方案

Winforms keeps an internal table that maps handles to control instances. That table ensures that a control (the form in your case) can never be garbage collected as long as the native window is alive. It gets removed from that table when the window is destroyed, either by the user closing the form or your code disposing it.

The System.Timers.Timer is kept alive by a cookie that's referenced by the CLR. The class is implemented with a System.Threading.Timer which has a constructor that takes a state object argument. That state object is the cookie, the CLR keeps it referenced with the equivalent of GCHandle.Alloc(). Disabling the timer resets the cookie which allows the timer to be garbage collected.

These are natural and necessary ways that the framework prevents these objects from getting garbage collected too early. You can only cause a leak by forgetting to disable the timer when the form is disposed. Which in general is quite unhealthy, you don't want a timer to keep ticking when the form is dead. Move the Dispose method from the Designer.cs file into the form code or override OnFormClosed() to disable the timer.

这篇关于垃圾收集和GCHandle.Alloc的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆