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。共有してくれてありがとう。ところで、あなた自身の答えを受け入れるかもしれません;) – Alex

答えて

7

Microsoftは確かに途中Vista上InitializeCriticalSection作品、Windows Server 2008を変更し、そしておそらくまた、Windows 7
てきた彼らは、あなたがCSの束を割り当てる際にデバッグ情報のために使用されるいくつかのメモリを保持するために、「機能」を追加しました。割り当てが増えるほど、より多くのメモリが保持されます。それは漸近的であり、最終的には平坦化されるかもしれない(これに完全に買われていない)。
この「機能」を回避するには、新しいAPI InitalizeCriticalSectionExを使用し、フラグCRITICAL_SECTION_NO_DEBUG_INFOを渡す必要があります。
この利点は、スピンカウントだけが実際に待機することなく使用されるため、高速である可能性があることです。
あなたの古いアプリケーションは互換性がないのであるため、コードを変更する必要があり、プラットフォームに依存するようになりました(使用するバージョンを確認するためにバージョンを確認する必要があります)。また、必要に応じてデバッグする能力を失います。

テストキットは、Windows Server 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ギガバイトとWin2008サーバーとクアッドCPUコアの凍結を参照してください。
-... Windows 2003サーバー上で繰り返し、魅力的なように扱います。

+0

こんにちはフランソワ、情報ありがとう。 Vista/Windows2008で実行しているときにInitializeCriticalSectionExを自動的に使用するために、Delphiのinitialization-sectionコードを貼り付けることができますか? – 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(真))。アプリケーションがクリティカルセクションの作成と削除を積極的に実行している間に、そのアプリケーションを監視しました。予想どおり、メモリ使用量は一定でした。 – Michael

+0

プロセスエクスプローラ(プライベートバイト)ですばらしい鋸歯を示すクリティカルセクションを作成して削除すると、上下に移動することが予想されます。 BTW私はそれが違いを生むならば、10,000,000でそれをやった。 –

2

あなたのテストはおそらく問題を代表するものではありません。クリティカルセクションは、クリティカルセクションを初期化するときに実際のカーネルミューテックスが作成されないため、「軽量ミューテックス」とみなされます。つまり、あなたの10Mクリティカルセクションは単純な構造のメンバーで構成されています。しかし、2つのスレッドが同時にCSにアクセスすると、それらを同期させるために、実際にミューテックスが作成されます。これは別の話です。

実際のアプリスレッドでは、テストアプリとは異なり、衝突すると想定しています。クリティカルセクションを軽量のミューテックスとして扱い、たくさんのセクションを作成している場合、アプリケーションは実際のカーネルミューテックスを多数割り当てている可能性があります。これは、ライトクリティカルセクションオブジェクトよりも重いです。 mutexはカーネルオブジェクトなので、それらの数が多すぎるとOSが壊れる可能性があります。

実際そうであれば、多くの衝突が予想されるクリティカルセクションの使用を減らす必要があります。これはWindows版とは関係がないため、私の推測は間違っているかもしれませんが、それでも考慮すべき点です。 OSのハンドル数を監視し、アプリの動作を確認してください。

+0

主なポイントは、(APIを呼び出すだけで)非常に同じコードはXP/2003ではうまく動作しますが、Vista/2008ではうまく動作しないということです。 –

+0

あなたのコードがどのように働いているのか分かりませんが、少なくとも繰り返しテストしてメモリを割り当てたり解放したりするテストアプリでは、メモリマネージャがOSに返すのではなく空きメモリをキャッシュしようとしている可能性がありますすぐに。 VistaとXPはおそらく異なるメモリマネージャを持っているため、違いがあります。実際のCSの代わりに同じサイズの他の任意の構造体を割り当てると同じことが起こりますか?あなたは実際にたくさんのハンドルが作成されているのを見ていますか? – eran