代码之家  ›  专栏  ›  技术社区  ›  josefx

内存不足

  •  5
  • josefx  · 技术社区  · 15 年前

    我目前正在调试一个多线程应用程序,它运行时不会出错,直到一些函数调用了大约2000次。之后,应用程序停止响应,我可以跟踪到“Beginthreadex失败并出现内存不足错误”。

    在ProcessExplorer中检查应用程序时,我可以看到越来越多的线程句柄被泄漏,并且在错误发生之前虚拟内存不断增长,专用字节保持在较低的水平。 泄漏的线程也会调用coInitialize,而从不调用couninitialize。

    我想知道的是:

    • 虚拟内存代表什么?
    • 虚拟内存是否与泄漏的线程句柄相关?
    • COM或MSXML6(由线程调用)是否复制线程句柄以及如何关闭它们?

    我希望我的问题是清楚的,不打破任何卢布,这是我的第一个问题,英语不是我的第一语言。-(

    我忘了提一下,一旦线程终止,我会关闭由beginthreadex返回的句柄,这会将打开的句柄数减少大约一半,但不会影响虚拟内存。 另外,在插入closehandle调用之前,processexplorer中显示的每个线程句柄的句柄数为2。

    编辑

    我以前不包括这一点,我觉得很愚蠢,我知道线程退出时,在使用Visual Studio进行调试时,活动线程的数量不会增加。我希望不是所有泄漏的内存都是由调用引起的 终止读,因为它们在一个相当大的库中使用,我不想修改它。

    到我问题的COM部分,用!htrace-diff我发现线程句柄由MSXML分配,但在函数调用结束后没有释放,它们是否与泄漏相关,或者稍后关闭?

    谢谢你的评论,虽然问题仍然存在,但他们帮助我更好地理解它。

    2 回复  |  直到 15 年前
        1
  •  4
  •   Chris Becke    15 年前

    进程可用的虚拟内存是4GB地址空间中的2GB。每个线程默认为其堆栈空间保留大约1MB的虚拟内存空间。因此,在虚拟内存耗尽之前,Win32应用程序的活动线程数限制为大约2000个。

    虚拟内存是应用程序在现代虚拟内存操作系统(如Windows)中获得的内存。在win32上发生的是,您的应用程序得到一个2GB的虚拟地址空间。当您的程序调用new或malloc时,在经过几个层的隧道挖掘之后,会在磁盘上为您的应用程序分配空间—在页面文件中。当CPU指令试图访问该内存时,硬件异常被抛出,内核将物理RAM分配给该区域,并从页面文件中读取内容。 因此,不管PC中的物理RAM如何,每个应用程序都认为它可以访问整个2GB。 虚拟内存是2GB空间已用光的数量。

    每个线程(见上文)保留1 MB的虚拟地址空间,以便其堆栈增长。其中大部分1MB只是保留空间(希望如此),没有RAM或页面文件的支持。

    关闭线程句柄时,不关闭线程。线程由另一个调用TerminateThread的线程终止(该线程泄漏线程堆栈和某些其他资源,因此永远不要使用它)、调用exitThread()本身或退出线程过程。

    因此,有了2000个调用限制、不匹配的coInitialize和couninitialize调用,我会说线程没有完全退出。2000个工作线程中的每一个在完成工作后都在做一些事情,而不是退出。

        2
  •  3
  •   interjay    15 年前

    这个 _beginthreadex / _endthreadex 函数不会自动关闭线程句柄,因此必须调用win32 CloseHandle 函数关闭它。句柄是返回的值 新开始 . 如果你使用 _beginthread / _endthread 相反,手柄将自动关闭。

    关于虚拟内存:它表示保留的内存,但还不一定要使用。泄漏的内存(或至少部分内存)与句柄泄漏有关。当线程的最后一个句柄关闭时,Windows将释放为其保留的虚拟内存。