UI线程.Invoke()导致句柄泄漏? [英] UI Thread .Invoke() causing handle leak?

查看:111
本文介绍了UI线程.Invoke()导致句柄泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在什么情况下,使用委托和.InvokeRequired时从非UI线程更新UI控件可能导致进程的句柄不断增加?

In what circumstances would updating a UI control from a non-UI thread could cause the processes' handles to continually increase, when using a delegate and .InvokeRequired?

例如:

public delegate void DelegateUIUpdate();
private void UIUpdate()
{
    if (someControl.InvokeRequired)
    {
        someControl.Invoke(new DelegateUIUpdate(UIUpdate));
        return;
    }
    // do something with someControl
}

在循环中或按计时器间隔调用此方法时,程序的句柄会不断增加.

When this is called in a loop or on timer intervals, the handles for the program consistently increase.

如果以上内容已被注释掉并作如下修改:

If the above is commented out and amended as such:

public delegate void DelegateUIUpdate();
private void UIUpdate()
{
    //if (someControl.InvokeRequired)
    //{
    //   someControl.Invoke(new DelegateUIUpdate(UIUpdate));
    //    return;
    //}
    CheckForIllegalCrossThreadCalls = false;
    // do something with someControl
}

...然后使句柄 stop 递增,但是我当然不想允许跨线程调用.

...then the handles stop incrementing, however I don't want to allow cross thread calls, of course.

以下是显示手柄增加的示例:

Here is a sample that shows the handles increase:

Thread thread;
private delegate void UpdateGUI();
bool UpdateTheGui = false;

public Form1()
{
    InitializeComponent();

    thread = new Thread(new ThreadStart(MyThreadLoop));
    thread.Start();
}

private void MyThreadLoop()
{
    while (true)
    {
        Thread.Sleep(500);
        if (UpdateTheGui)
        {
            UpdateTheGui = false;
            UpdateTheGuiNow();
        }
    }
}

private void UpdateTheGuiNow()
{
    if (label1.InvokeRequired)
    {
        label1.Invoke(new UpdateGUI(UpdateTheGuiNow));
        return;
    }

    label1.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
    label2.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
    label3.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
}

private void btnInvoke_Click(object sender, EventArgs e)
{
    UpdateTheGui = true;
}

推荐答案

Control.Invoke()方法不使用任何句柄.但是,显然是从线程中调用此代码的.线程确实消耗其中的5个句柄.

The Control.Invoke() method doesn't consume any handles. However, this code is clearly called from a thread. A Thread does consume handles, 5 of them.

尽管Thread类应该有一个Dispose()方法,但它没有.那可能是设计使然,对于线程池线程来说,可靠地,不可能地调用是非常困难的.终结器释放线程所需的5个句柄.如果终结器从不运行,您的程序将需要不断增加的句柄.

The Thread class doesn't have a Dispose() method, although it ought to have one. That was probably by design, it would be very difficult to call reliably, impossibly so for threadpool threads. The 5 handles that a thread requires are released by the finalizer. Your program will require ever increasing amounts of handles if the finalizer never runs.

不让finalizer运行很不寻常.您将必须有一个程序,该程序可以启动许多线程,但不会分配大量内存.这往往仅在静态测试中发生.您可以使用Perfmon.exe诊断这种情况,使用.NET内存性能计数器并检查是否已完成gen#0收集.

Not getting the finalizer to run is quite unusual. You would have to have a program that starts a lot of threads but doesn't allocate a lot of memory. This tends to only happen in static tests. You can diagnose this condition with Perfmon.exe, use the .NET memory performance counters and check if gen #0 collections are being done.

如果这在生产程序中发生,那么您必须自己调用GC.Collect(),以免发生句柄泄漏.

If this happens in a production program then you'll have to call GC.Collect() yourself to avoid a runaway handle leak.

这篇关于UI线程.Invoke()导致句柄泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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