似乎在Vista / Windows Server 2008中使用关键部分会导致操作系统无法完全恢复内存。 我们在Delphi应用程序中发现了这个问题,显然是因为使用了CS API。 (见SO question)
还有其他人用其他语言开发的应用程序(C ++,...)吗?
示例代码只是初始化10000000 CS,然后删除它们。这在XP / Win2003中运行良好,但在应用程序结束之前不会释放Vista / Win2008中的所有峰值内存。
使用CS的次数越多,您的应用程序就会越多地保留内存。
答案 0 :(得分:7)
微软确实改变了InitializeCriticalSection
在Vista,Windows Server 2008以及Windows 7上的工作方式
他们添加了一个“功能”,以便在分配一堆CS时保留用于调试信息的一些内存。分配的越多,保留的内存就越多。它可能是渐近的并最终变平(没有完全买到这个)
要避免使用此“功能”,您必须使用新的API InitalizeCriticalSectionEx并传递标记CRITICAL_SECTION_NO_DEBUG_INFO
。
这样做的好处是它可能更快,因为通常只使用spincount而不必实际等待。
缺点是您的旧应用程序可能不兼容,您需要更改代码,现在它依赖于平台(您必须检查版本以确定使用哪个版本)。如果需要,你也失去了调试能力。
冻结Windows Server 2008的测试工具包:
- 将此C ++示例构建为CSTest.exe
#include "stdafx.h"
#include "windows.h"
#include <iostream>
using namespace std;
void TestCriticalSections()
{
const unsigned int CS_MAX = 5000000;
CRITICAL_SECTION* csArray = new CRITICAL_SECTION[CS_MAX];
for (unsigned int i = 0; i < CS_MAX; ++i)
InitializeCriticalSection(&csArray[i]);
for (unsigned int i = 0; i < CS_MAX; ++i)
EnterCriticalSection(&csArray[i]);
for (unsigned int i = 0; i < CS_MAX; ++i)
LeaveCriticalSection(&csArray[i]);
for (unsigned int i = 0; i < CS_MAX; ++i)
DeleteCriticalSection(&csArray[i]);
delete [] csArray;
}
int _tmain(int argc, _TCHAR* argv[])
{
TestCriticalSections();
cout << "just hanging around...";
cin.get();
return 0;
}
-...运行此批处理文件(需要来自服务器SDK的sleep.exe)
@rem you may adapt the sleep delay depending on speed and # of CPUs
@rem sleep 2 on a duo-core 4GB. sleep 1 on a 4CPU 8GB.
@for /L %%i in (1,1,300) do @echo %%i & @start /min CSTest.exe & @sleep 1
@echo still alive?
@pause
@taskkill /im cstest.* /f
-...并在启动300个实例之前看到一个8GB和四核CPU核心冻结的Win2008服务器 -...在Windows 2003服务器上重复,并看到它像魅力一样处理它。
答案 1 :(得分:2)
您的测试很可能无法代表问题。关键部分被视为“轻量级互斥锁”,因为初始化关键部分时不会创建真正的内核互斥锁。这意味着您的10M关键部分只是具有一些简单成员的结构。但是,当两个线程同时访问一个CS时,为了同步它们,确实创建了一个互斥锁 - 这是一个不同的故事。
我认为在您的真实应用程序中,线程会发生冲突,而不是您的测试应用程序。现在,如果您真的将关键部分视为轻量级互斥体并创建了大量的互斥体,那么您的应用程序可能会分配大量真正的内核互斥体,这些互斥体比轻型关键部分对象更重。而且由于互斥体是内核对象,因此创建过多的互斥体确实会对操作系统造成伤害。
如果确实如此,那么您应该减少预期会发生大量冲突的关键部分的使用。这与Windows版本无关,所以我的猜测可能是错的,但它仍然需要考虑。尝试监视操作系统句柄计数,并查看应用程序的运行情况。
答案 2 :(得分:1)
你正在看别的东西。
我刚建成&amp;运行此测试代码。每个内存使用情况都是常量 - 私有字节,工作集,提交等。
int _tmain(int argc, _TCHAR* argv[])
{
while (true)
{
CRITICAL_SECTION* cs = new CRITICAL_SECTION[1000000];
for (int i = 0; i < 1000000; i++) InitializeCriticalSection(&cs[i]);
for (int i = 0; i < 1000000; i++) DeleteCriticalSection(&cs[i]);
delete [] cs;
}
return 0;
}