我在Windows Server 2003服务器(X64)上运行64位多线程程序,遇到一些线程似乎在malloc或free函数中被永久阻塞的情况。堆栈跟踪如下:
ntdll.dll!NtWaitForSingleObject() + 0xa bytes
ntdll.dll!RtlpWaitOnCriticalSection() - 0x1aa bytes
ntdll.dll!RtlEnterCriticalSection() + 0xb040 bytes
ntdll.dll!RtlpDebugPageHeapAllocate() + 0x2f6 bytes
ntdll.dll!RtlDebugAllocateHeap() + 0x40 bytes
ntdll.dll!RtlAllocateHeapSlowly() + 0x5e898 bytes
ntdll.dll!RtlAllocateHeap() - 0x1711a bytes
MyProg.exe!malloc(unsigned __int64 size=0) Line 168 C
MyProg.exe!operator new(unsigned __int64 size=1) Line 59 + 0x5 bytes C++
ntdll.dll!NtWaitForSingleObject()
ntdll.dll!RtlpWaitOnCriticalSection()
ntdll.dll!RtlEnterCriticalSection()
ntdll.dll!RtlpDebugPageHeapFree()
ntdll.dll!RtlDebugFreeHeap()
ntdll.dll!RtlFreeHeapSlowly()
ntdll.dll!RtlFreeHeap()
MyProg.exe!free(void * pBlock=0x000000007e8e4fe0) C
顺便说一句,传递给新运算符的参数值在这里可能不正确,可能是由于优化。
另外,与此同时,我发现在进程资源管理器中,该程序的虚拟大小为10GB,但私有字节和工作集非常小(<2GB)。我们确实有一些线程使用virtualalloc但是以一种在调用中提交内存的方式,并且这些线程没有被阻塞。
m_pBuf = VirtualAlloc(NULL, m_size, MEM_COMMIT, PAGE_READWRITE);
......
VirtualFree(m_pBuf, 0, MEM_RELEASE);
这对我来说很奇怪,似乎有很多虚拟空间被保留但未提交,而malloc / free被锁定。我猜测内存/对象是否有任何损坏,所以计划打开带有pageheap的gflag来解决这个问题。
之前有没有人有类似的经历?你能跟我分享一下吗?我可能会得到更多提示吗?
非常感谢!
答案 0 :(得分:2)
您的程序正在使用PageHeap,它仅用于调试并且会产生大量内存开销。要查看已激活PageHeap的程序,请在命令行执行此操作。
% Gflags.exe /p
要为您的进程禁用它,请键入此内容(对于MyProg.exe):
% Gflags.exe /p /disable MyProg.exe
答案 1 :(得分:1)
Pageheap.exe检测到大多数与堆相关的错误 - 尝试Pageheap
此外,您应该查看“传递给新...的参数值” - 在调试模式下是否会发生此损坏?确保禁用所有优化。
答案 2 :(得分:1)
如果你的系统内存不足,可能是操作系统交换的情况,这意味着对于单个分配,在最坏的情况下,操作系统可能需要找到交换的最佳候选者,将其写入磁盘,释放内存并将其返回。你确定它是锁定的还是只是表现得很慢?另外一个线程可以将内存交换到磁盘,而这两个线程等待它调用malloc/free
来完成吗?
答案 3 :(得分:1)
我在本机应用程序中调试泄漏的首选解决方案是使用UMDH获取进程中用户模式堆的连续快照,然后再次运行UMDH以区分快照。快照中的任何变化模式都可能是泄漏。
你可以通过分配调用堆来获得内存块的计数和大小,因此可以非常直接地查看最大的生猪位置。
用户模式转储堆(UMDH)实用程序 与操作系统一起使用 分析a的Windows堆分配 具体过程。