Domanda

Sembra che l'uso di Sezioni critiche un po 'in Vista / Windows Server 2008 porti il ??sistema operativo a non recuperare completamente la memoria. Abbiamo riscontrato questo problema con un'applicazione Delphi ed è chiaramente a causa dell'utilizzo dell'API CS. (vedi SO domanda )

Qualcun altro l'ha visto con applicazioni sviluppate con altre lingue (C ++, ...)?

Il codice di esempio stava appena inizializzando 10000000 CS, quindi eliminandoli. Funziona bene in XP / Win2003 ma non rilascia tutta la memoria di picco in Vista / Win2008 fino al termine dell'applicazione.
Più usi CS, più l'applicazione conserva la memoria per nulla.

È stato utile?

Soluzione

Microsoft ha davvero cambiato il modo in cui InitializeCriticalSection funziona su Vista, Windows Server 2008 e probabilmente anche Windows 7.
Hanno aggiunto una "funzione" per conservare parte della memoria utilizzata per le informazioni di debug quando si alloca un gruppo di CS. Più si alloca, più memoria viene mantenuta. Potrebbe essere asintotico e infine appiattirsi (non completamente acquistato per questo).
Per evitare questa "funzionalità", devi utilizzare la nuova API InitalizeCriticalSectionEx e passa il flag CRITICAL_SECTION_NO_DEBUG_INFO .
Il vantaggio è che potrebbe essere più veloce in quanto, molto spesso, verrà utilizzato solo lo spincount senza dover effettivamente attendere.
Gli svantaggi sono che le tue vecchie applicazioni possono essere incompatibili , è necessario modificare il codice e ora dipende dalla piattaforma (è necessario verificare la versione per determinare quale utilizzare). E perdi anche la possibilità di eseguire il debug in caso di necessità.

Kit di test per congelare un Windows Server 2008:
- crea questo esempio C ++ come 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; 
}

-... Esegui questo file batch (richiede il file sleep.exe dall'SDK del server)

@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

-... e vedi un server Win2008 con 8 GB e il core quad CPU congelato prima di raggiungere le 300 istanze lanciate.
-... ripeti su un server Windows 2003 e vedilo gestirlo come un fascino.

Altri suggerimenti

Molto probabilmente il tuo test non è rappresentativo del problema. Le sezioni critiche sono considerate "mutex leggeri". perché un vero mutex del kernel non viene creato quando si inizializza la sezione critica. Ciò significa che le sezioni critiche 10M sono solo strutture con pochi membri semplici. Tuttavia, quando due thread accedono a un CS contemporaneamente, per sincronizzarli viene effettivamente creato un mutex - e questa è una storia diversa.

Presumo che le discussioni della tua vera app si scontrino, al contrario della tua app di prova. Ora, se stai davvero trattando le sezioni critiche come mutex leggeri e ne crei molte, la tua app potrebbe allocare un gran numero di mutex reali del kernel, che sono molto più pesanti dell'oggetto sezione critica. E poiché i mutex sono oggetti del kernel, crearne un numero eccessivo può davvero danneggiare il sistema operativo.

Se questo è davvero il caso, dovresti ridurre l'uso di sezioni critiche in cui ti aspetti molte collisioni. Questo non ha nulla a che fare con la versione di Windows, quindi la mia ipotesi potrebbe essere sbagliata, ma è ancora qualcosa da considerare. Prova a monitorare il conteggio degli handle del sistema operativo e guarda come sta andando la tua app.

Stai vedendo qualcos'altro.

Ho appena creato & amp; ha eseguito questo codice di prova. Ogni stat di utilizzo della memoria è costante: byte privati, working set, commit e così via.

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top