質問

Vista / Windows Server 2008でクリティカルセクションをかなり使用すると、OSがメモリを完全に取り戻せないようです。 Delphiアプリケーションでこの問題が見つかりましたが、これは明らかにCS APIを使用しているためです。 (こちらをご覧ください SO質問

他の言語(C ++、...)で開発されたアプリケーションで他の誰かがそれを見たことがありますか?

サンプルコードは、単に10000000 CSを初期化してから削除していました。これはXP / Win2003で正常に動作しますが、アプリケーションが終了するまでVista / Win2008のすべてのピークメモリを解放しません。
CSを使用すればするほど、アプリケーションはメモリを何も保持しなくなります。

役に立ちましたか?

解決

Microsoftは、 InitializeCriticalSection がVista、Windows Server 2008、およびおそらくWindows 7で動作する方法を実際に変更しました。
彼らは「機能」を追加しました;多数のCSを割り当てるときに、デバッグ情報に使用されるメモリを保持します。より多くのメモリを割り当てると、より多くのメモリが保持されます。それは漸近的であり、最終的には平坦になる可能性があります(これに完全には購入されていません)。
この「機能」を回避するには、新しいAPI InitalizeCriticalSectionEx にフラグ CRITICAL_SECTION_NO_DEBUG_INFO を渡します。
これの利点は、実際に待機することなくスピンカウントのみが使用されるため、非常に高速になる可能性があることです。
欠点は、古いアプリケーションに互換性がない可能性があることです。コードを変更する必要があり、プラットフォームに依存するようになりました(使用するバージョンを決定するにはバージョンを確認する必要があります)。また、必要に応じてデバッグすることもできなくなります。

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サーバーで繰り返し、それが魅力のように処理されるのを確認します。

他のヒント

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

実際のアプリでは、テストアプリとは対照的に、スレッドが衝突すると想定しています。さて、クリティカルセクションを実際に軽量のmutexとして扱い、それらを大量に作成する場合、アプリはライトクリティカルセクションオブジェクトよりもかなり重い多数の実際のカーネルmutexを割り当てている可能性があります。そして、ミューテックスはカーネルオブジェクトであるため、ミューテックスを過剰に作成すると、OSを本当に傷つける可能性があります。

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

別のものが表示されています。

構築したばかりの&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;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top