![](/img/trans.png)
[英]Thread handle leak in .Net service (Not win32 threads. i.e not observable in Task Manager)
[英]Handle leak in .Net threads
这实际上咬了我几次。 如果你做这样的简单代码:
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 1000000; i++)
{
Thread CE = new Thread(SendCEcho);
CE.Priority = ThreadPriority.Normal;
CE.IsBackground = true;
CE.Start();
Thread.Sleep(500);
GC.Collect();
}
}
private void SendCEcho()
{
int Counter = 0;
for (int i = 0; i < 5; i++)
{
Counter++;
Thread.Sleep(25);
}
}
运行此代码并观察手柄飞! Thread.Sleep是这样你可以关闭它,它不会接管你的电脑。 这应该保证在下一个线程启动之前启动的线程死掉。 调用GC.Collect(); 什么也没做。 根据我的观察,这个代码在正常刷新时每次刷新任务管理器时都会丢失10个句柄。
无效SendCEcho()函数中的内容无关紧要,如果需要,则计为5。 当线程死亡时,有一个手柄无法清理。
对于大多数程序而言,这并不重要,因为它们不会长时间运行。 在我创建的一些程序中,它们需要运行数月和数月。
如果反复运用此代码,最终可能会将句柄泄漏到Windows操作系统变得不稳定的位置,并且它将无法运行。 需要重新启动。
我确实通过使用线程池和这样的代码解决了这个问题:
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadJobMoveStudy));
我的问题是为什么.Net中存在这样的泄漏,为什么它存在这么长时间? 既然喜欢1.0? 我在这里找不到答案。
你正在创建永不结束的线程。 SendCEcho
的for循环永远不会终止,因此线程永远不会结束,因此无法回收。 如果我修复你的循环代码,那么线程完成并按预期回收。 我无法使用下面的代码重现问题。
static void SendCEcho()
{
int Counter = 0;
for (int i = 0; i < 5; i++)
{
Counter++;
Thread.Sleep(25);
}
}
for (int i = 0; i < 5 + i++; )
相当奇怪的错字,你没有重新创造你真正的问题。 有一个,Thread对象消耗5个操作系统句柄,其内部终结器释放它们。 .NET类通常具有Dispose()方法,以确保可以提前释放此类句柄,但Thread没有。 这是勇敢的设计,这样的Dispose()方法将很难调用。
所以不得不依赖终结器是一项艰难的要求。 在具有“SendEcho”方法的程序中,并且不执行任何其他操作,您将面临垃圾收集器永远不会运行的风险。 所以终结者无法完成它的工作。 然后由您自己调用GC.Collect()。 你会考虑这样做,比如你开始的1000个线程。 或者使用ThreadPool.QueueUserWorkItem()或Task.Run(),以便回收线程,即逻辑方法。
使用Perfmon.exe验证GC确实不运行。 为您的程序添加.NET CLR Memory>#Gen 0 Collections计数器。
尝试添加GC.WaitForPendingFinalizers();
在你调用GC.Collect()之后; 我想这会让你得到你想要的东西。 完整来源如下:
编辑
另请参阅2005年的这篇文章: https : //bytes.com/topic/net/answers/106014-net-1-1-possibly-1-0-also-threads-leaking-event-handles-bug 。 几乎与您的代码完全相同。
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 1000000; i++)
{
Thread CE = new Thread(SendCEcho);
CE.Priority = ThreadPriority.Normal;
CE.IsBackground = true;
CE.Start();
Thread.Sleep(500);
CE = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
public static void SendCEcho()
{
int Counter = 0;
for (int i = 0; i < 5; i++ )
{
Counter++;
Thread.Sleep(25);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.