为什么threadpool.QueueUserWorkItem创建了这么多的事件句柄?

时间:2014-01-16 03:21:54

标签: c# .net windows multithreading windbg

我写了一个程序,每1秒调用ThreadPool.QueueUserWorkItem。但是,它会导致大量消耗事件句柄。

class Program
{
    private static Timer _timer;

    static void Main(string[] args)
    {
        _timer = new Timer(Run, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
        _timer.Change(new TimeSpan(0, 0, 0, 1), Timeout.InfiniteTimeSpan);

        Console.ReadLine();
        _timer.Dispose();
    }

    static void Run(object state)
    {
        ThreadPool.QueueUserWorkItem((object statex) =>
            {
                int s = 0;
                for (int i = 0; i < 1000; ++i)
                {
                    int j = i*i;
                    s += j;
                }
                Console.WriteLine(s);
            });

        _timer.Change(new TimeSpan(0, 0, 0, 1), Timeout.InfiniteTimeSpan);
    }
}

通过使用windbg的!htrace -diff命令,我发现在两个快照之间创建了很多事件句柄,而!htrace -diff确保所有这些句柄都没有关闭。句柄如下:

Handle = 0x00000000000003d0 - OPEN
Thread ID = 0x00000000000046a0, Process ID = 0x0000000000003f50

0x000007fd7932306a: ntdll!ZwCreateEvent+0x000000000000000a
0x000007fd766126cf: KERNELBASE!CreateEventW+0x0000000000000063
0x000007fd6ee0d647: clr!CLREventBase::CreateManualEvent+0x0000000000000028
0x000007fd6ee0e33f: clr!Thread::AllocHandles+0x000000000000005f
0x000007fd6ee0f231: clr!Thread::CreateNewOSThread+0x0000000000000091
0x000007fd6ee0f152: clr!Thread::CreateNewThread+0x00000000000000ae
0x000007fd6ee0f9b1: clr!ThreadpoolMgr::CreateUnimpersonatedThread+0x00000000000000c5
0x000007fd6ee0cccc: clr!ThreadpoolMgr::CreateWorkerThread+0x0000000000000019
0x000007fd6ee0cca5: clr!ThreadpoolMgr::MaybeAddWorkingWorker+0x000000000000011d
0x000007fd6ee0d398: clr!ManagedPerAppDomainTPCount::SetAppDomainRequestsActive+0x0000000000000024
0x000007fd6ee0d436: clr!ThreadpoolMgr::SetAppDomainRequestsActive+0x000000000000002a
0x000007fd6ee0d3d2: clr!ThreadPoolNative::RequestWorkerThread+0x000000000000002f
0x000007fd6dc062ea: mscorlib_ni+0x00000000005662ea
0x000007fd6db3c53e: mscorlib_ni+0x000000000049c53e
……….
Handle = 0x00000000000003cc - OPEN
Thread ID = 0x00000000000046a0, Process ID = 0x0000000000003f50

0x000007fd7932306a: ntdll!ZwCreateEvent+0x000000000000000a
0x000007fd766126cf: KERNELBASE!CreateEventW+0x0000000000000063
0x000007fd6ee0d647: clr!CLREventBase::CreateManualEvent+0x0000000000000028
0x000007fd6ee0e331: clr!Thread::AllocHandles+0x0000000000000051
0x000007fd6ee0f231: clr!Thread::CreateNewOSThread+0x0000000000000091
0x000007fd6ee0f152: clr!Thread::CreateNewThread+0x00000000000000ae
0x000007fd6ee0f9b1: clr!ThreadpoolMgr::CreateUnimpersonatedThread+0x00000000000000c5
0x000007fd6ee0cccc: clr!ThreadpoolMgr::CreateWorkerThread+0x0000000000000019
0x000007fd6ee0cca5: clr!ThreadpoolMgr::MaybeAddWorkingWorker+0x000000000000011d
0x000007fd6ee0d398: clr!ManagedPerAppDomainTPCount::SetAppDomainRequestsActive+0x0000000000000024
0x000007fd6ee0d436: clr!ThreadpoolMgr::SetAppDomainRequestsActive+0x000000000000002a
0x000007fd6ee0d3d2: clr!ThreadPoolNative::RequestWorkerThread+0x000000000000002f
0x000007fd6dc062ea: mscorlib_ni+0x00000000005662ea
0x000007fd6db3c53e: mscorlib_ni+0x000000000049c53e

通过使用!handle,我找到了124个事件句柄:

187 Handles
Type                 Count
None                 3
Event                124
Section              4
File                 7
Directory            3
Mutant               4
WindowStation        2
Semaphore            2
Key                  10
Thread               21
Desktop              1
IoCompletion         2
Timer                3
TpWorkerFactory      1

所以,我真的很想知道为什么QueueUserWorkItem会创建如此多的事件句柄???这是一个错误还是CLR的设计? 在我们的制作服务上,由于我们使用async操作很多,基本上每个async操作都会调用CLR的QueueUserWorkItem。我认为这就是为什么我们的服务有超过60000个句柄的原因。但是,如果我真的想减少手柄的数量呢?这么多句柄在内核内存中会有很多对象,我真的想减少内存使用量。

0 个答案:

没有答案