JYe*_*ton 8 c# multithreading memory-leaks handles
在什么情况下,在使用委托时,从非UI线程更新UI控件可能会导致进程的句柄不断增加.InvokeRequired?
例如:
public delegate void DelegateUIUpdate();
private void UIUpdate()
{
if (someControl.InvokeRequired)
{
someControl.Invoke(new DelegateUIUpdate(UIUpdate));
return;
}
// do something with someControl
}
Run Code Online (Sandbox Code Playgroud)
在循环或定时器间隔中调用此方法时,程序的句柄会持续增加.
编辑:
如果以上内容被注释掉并进行了修改:
public delegate void DelegateUIUpdate();
private void UIUpdate()
{
//if (someControl.InvokeRequired)
//{
// someControl.Invoke(new DelegateUIUpdate(UIUpdate));
// return;
//}
CheckForIllegalCrossThreadCalls = false;
// do something with someControl
}
Run Code Online (Sandbox Code Playgroud)
...然后句柄停止递增,当然我不想允许跨线程调用.
编辑2:
这是一个显示句柄增加的示例:
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;
}
Run Code Online (Sandbox Code Playgroud)
Control.Invoke() 方法不消耗任何句柄。然而,这段代码显然是从线程中调用的。一个线程确实会消耗句柄,其中有 5 个。
Thread 类没有 Dispose() 方法,尽管它应该有一个方法。这可能是设计使然,对于线程池线程来说,可靠地调用是非常困难的,这是不可能的。线程所需的 5 个句柄由终结器释放。如果终结器从不运行,您的程序将需要不断增加的句柄数量。
不让终结器运行是很不寻常的。您必须有一个启动大量线程但不分配大量内存的程序。这往往只发生在静态测试中。您可以使用 Perfmon.exe 诊断此情况,使用 .NET 内存性能计数器并检查第 0 代收集是否正在完成。
如果这种情况发生在生产程序中,那么您必须自己调用 GC.Collect() 以避免失控句柄泄漏。