5

Vista/Windows Server 2008에서 크리티컬 섹션을 사용하면 OS가 메모리를 완전히 되찾지 못하는 것으로 보입니다. 이 문제는 Delphi 응용 프로그램에서 발견되었으며 이는 CS API를 사용했기 때문에 분명합니다. (SO question 참조)Vista/Win2008에서 중요 섹션 누출?

다른 사람이 다른 언어 (C++, ...)로 개발 한 응용 프로그램을 본적이 있습니까?

예제 코드는 10000000 CS를 초기화 한 다음 삭제하는 것입니다. 이 XP/Win2003 잘 작동하지만 응용 프로그램이 끝날 때까지 Vista/Win2008 모든 피크 메모리 해제하지 않습니다.
CS를 많이 사용할수록 더 많은 응용 프로그램이 메모리를 유지합니다.

+0

안녕하세요, François. 이 문제에 대한 소식이 있습니까? 나는 호기심 :) – Alex

+0

내 대답보기. "it's-a-feature-not-a-bug"카테고리에 실제로 변화가있었습니다 .... –

+0

안녕하세요, François. 공유해 주셔서 감사합니다. BTW, 당신은 당신의 자신의 대답을 수락하실 수 있습니다;) – Alex

답변

7

마이크로 소프트는 실제로 윈도우 서버 2008, Vista에서 길을 InitializeCriticalSection 작품을 변경하고, 아마도
윈도우 7 그들은 당신이 CS의 무리를 할당 할 때 디버그 정보를 사용하는 일부 메모리를 유지하기 "기능"추가. 더 많이 할당할수록 더 많은 메모리가 유지됩니다. 점근 적이며 결국은 평평해질 수 있습니다.
이 '기능'을 사용하지 않으려면 새 API InitalizeCriticalSectionEx을 사용하고 CRITICAL_SECTION_NO_DEBUG_INFO 플래그를 전달해야합니다.
이점은 실제로 기다릴 필요없이 spincount 만 사용되므로 더 빠를 수도 있다는 것입니다.
단점은 이전 응용 프로그램이 호환되지 않을 수 있습니다., 코드를 변경해야하며 플랫폼에 따라 달라집니다 (사용할 버전을 결정하기 위해 버전을 확인해야 함). 또한 필요한 경우 디버그 기능을 사용할 수 없습니다.

테스트 키트는 윈도우 서버 2008 동결 :
을 - 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; 
} 

으로이 C++ 예제를 빌드 -...이 배치 파일을 실행 (수면이 필요합니다.서버 SDK에서 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 개 인스턴스를 도달하기 전에 8 기가 바이트 쿼드 CPU 코어 동결과 Win2008 서버를 참조하십시오.
-... Windows 2003 서버에서 반복하면 매력처럼 처리됩니다.

+0

프랑소와 안녕, 정보 주셔서 감사합니다. Vista/Windows2008에서 실행될 때 InitializeCriticalSectionEx를 자동으로 사용하도록 델파이 '초기화'섹션 코드를 붙여 넣을 수 있습니까? – carlmon

1

다른 것을 볼 수 있습니다.

방금 ​​만든이 테스트 코드 &. 모든 메모리 사용 통계는 개인 바이트, 작업 세트, 커밋 등 상수입니다.

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; 
} 
+0

감사합니다 마이클. CS 테스트를 실행하는 동안 응용 프로그램이 시작되고 유휴 상태 일 때 응용 프로그램의 메모리를 모니터링했는지, 그리고 유휴 상태에서도 여전히 종료되지 않은 상태에서 응용 프로그램의 메모리를 모니터링 했습니까? 앱이 종료 된 후 메모리는 항상 완전히 복구됩니다. 문제는 CS를 많이 사용한 후에도 여전히 활성화 된 경우입니다. (희망이 분명하다) –

+0

무한 루프 (while (true))에 주목하자. 응용 프로그램이 중요 섹션을 만들고 삭제하는 동안 그것을 모니터링했습니다. 예상대로 메모리 사용이 일정했습니다. – Michael

+0

프로세스 탐색기 (개인 바이트)에서 멋진 톱니를 보여주는 중요 섹션을 만들고 삭제할 때 위아래로 갈 것으로 예상됩니다. BTW 차이가 나는 경우 10,000,000으로했습니다. –

2

테스트가 문제의 원인 일 수는 없습니다. 중요한 섹션을 초기화 할 때 실제 커널 뮤텍스가 생성되지 않기 때문에 중요한 섹션은 "경량 뮤텍스"로 간주됩니다. 즉, 10M 중요한 섹션은 몇 개의 간단한 멤버가있는 구조체입니다. 그러나 두 개의 스레드가 동시에 CS에 액세스 할 때 동기화하기 위해 뮤텍스가 실제로 생성됩니다. 이것은 다른 이야기입니다.

테스트 앱과는 달리 실제 앱 스레드가 충돌한다고 가정합니다. 이제 중요한 섹션을 경량 뮤텍스로 취급하고 많은 섹션을 만드는 경우 앱에서 많은 수의 실제 커널 뮤텍스를 할당 할 수 있습니다.이 뮤텍스는 경량 섹션 개체보다 무겁습니다. 뮤텍스는 커널 객체이기 때문에 과도한 수의 객체를 생성하면 OS가 손상 될 수 있습니다.

실제로 이러한 경우 충돌이 예상되는 중요한 섹션의 사용을 줄여야합니다. 이것은 Windows 버전과 아무런 관련이 없으므로 내 추측은 잘못되었을 수도 있지만 여전히 고려해야 할 사항입니다. OS 핸들 수를 모니터링하고 앱이 어떻게 작동하는지 확인해보십시오.

+0

요점은 API를 호출하는 바로 그 코드가 XP/2003에서는 잘 작동하지만 Vista/2008에서는 제대로 작동하지 않는다는 것입니다. –

+0

코드가 어떻게 작동하는지는 모르지만 적어도 메모리를 반복적으로 할당하고 해제하는 테스트 응용 프로그램의 경우 메모리 관리자가 필요없는 것으로 가정하고 사용 가능한 메모리를 OS로 반환하는 대신 메모리를 캐시하려고 할 가능성이 있습니다 곧. Vista와 XP에는 다른 메모리 관리자가 있으므로 차이점이 있습니다. 실제 CS가 아닌 같은 크기의 다른 임의의 구조를 할당 할 때도 같은 일이 발생합니까? 실제로 많은 핸들이 생성되는 것을 보시겠습니까? – eran