我目前正在调试一个多线程应用程序,它运行时没有错误,直到一些函数被调用大约2000次。之后,应用程序停止响应,我可以追溯到_beginthreadex失败并出现内存不足错误。
在ProcessExplorer中检查应用程序时,我可以看到越来越多的线程句柄泄漏,并且虚拟内存不断增长,直到错误发生,私有字节保持低位。 泄露的线程也调用CoInitialize,从不调用CoUninitialize。
我想知道的是:
我希望我的问题很明确,不会破坏任何问题,这是我的第一个问题,英语不是我的第一语言。:-(
我忘了提一下,一旦线程终止,我关闭_beginthreadex返回的句柄,这会将打开句柄的数量减少一半,但不会影响虚拟内存。 此外,在我插入CloseHandle调用之前,ProcessExplorer中显示的每个线程句柄的线程句柄数为2。
修改
之前没有包括这个,我感到愚蠢,我知道线程退出时活动线程的数量与Visual Studio调试时不会增长。我希望并非所有泄露的内存都是通话的结果 到TerminateThread,因为它们在一个相当大的库中使用,我宁愿不修改它。
对于我的问题的com部分,使用!htrace -diff,我发现msxml分配的线程句柄但在函数调用结束后没有释放,它们是否与泄漏有关,或者它们将在以后关闭?
感谢所有这些评论,虽然问题仍然存在,但他们帮助我更好地理解。
答案 0 :(得分:4)
进程可用的虚拟内存是4Gb地址空间的2Gb。默认情况下,每个线程为其堆栈空间保留大约1Mb的虚拟内存空间。因此,在虚拟内存耗尽之前,win32应用程序有大约2000个活动线程的限制。
虚拟内存是应用程序在现代虚拟内存操作系统中获得的内存,就像Windows一样。在Win32上发生的是,您的应用程序获得2Gb虚拟地址空间。当你的程序调用new或malloc时,在隧道传输多个层后,在磁盘上为你的应用程序分配空间 - 在页面文件中。当CPU指令尝试访问该内存时,会抛出硬件异常并且内核将物理RAM分配给该区域,并从页面文件中读取内容。 因此,无论PC中的物理RAM如何,每个应用程序都认为它可以访问整个2Gb。 虚拟内存是您的2Gb空间耗尽量的计数。
每个线程(见上文)为其堆栈预留1 Mb的虚拟地址空间。大多数1Mb只是保留空间(希望如此),没有RAM或页面文件的支持。
关闭线程句柄时,不要关闭线程。线程由另一个调用TerminateThread的线程终止(它会泄漏线程堆栈和其他一些资源,所以永远不要使用它),自己调用ExitThread(),或者退出ThreadProc。
因此,使用2000个调用限制,无法比拟的CoInitialize和CoUninitialize调用,我会说你的线程没有干净地退出或根本没有。 2000个工作线程中的每一个都在做完某事而不是在完成工作后退出。
答案 1 :(得分:3)
_beginthreadex
/ _endthreadex
函数不会自动关闭线程句柄,因此您必须调用win32 CloseHandle
函数来关闭它。句柄是_beginthreadex
返回的值。如果您使用_beginthread
/ _endthread
,则会自动关闭句柄。
关于虚拟内存:它表示已保留的内存,但尚未使用。泄漏的内存(或至少部分内存)与手柄泄漏有关。当线程的最后一个句柄关闭时,Windows将释放为其保留的虚拟内存。