5

Sembra che l'utilizzo di sezioni critiche piuttosto in Vista/Windows Server 2008 porti al sistema operativo che non riguadagna completamente la memoria. Abbiamo riscontrato questo problema con un'applicazione Delphi ed è chiaramente dovuto all'utilizzo dell'API CS. (Vedi questo SO question)Sezioni critiche che perdono memoria su Vista/Win2008?

Qualcun altro ha visto con le applicazioni sviluppate con altri linguaggi (C++, ...)?

Il codice di esempio è stata appena initialzing 10000000 CS, quindi eliminarli. Funziona bene in XP/Win2003 ma non rilascia tutta la memoria di picco in Vista/Win2008 fino alla fine dell'applicazione.
Più si utilizza CS, più l'applicazione conserva memoria per niente.

+0

Ciao, François. Avete notizie su questo problema? Sono curioso :) – Alex

+0

Vedi la mia risposta. C'era davvero un cambiamento nella categoria "it's-a-feature-not-a-bug" ... –

+0

Ciao, François. Grazie per la condivisione. A proposito, è possibile accettare la propria risposta;) – Alex

risposta

7

Microsoft hanno infatti cambiato il modo InitializeCriticalSection opere su Vista, Windows Server 2008, e probabilmente anche Windows 7.
hanno aggiunto una "caratteristica" di mantenere una certa memoria utilizzata per le informazioni di debug quando si assegna un gruppo di CS. Più si assegna, più memoria viene mantenuta. Potrebbe essere asintotico e alla fine appiattirsi (non completamente acquistato per questo).
Per evitare questo "caratteristica", è necessario utilizzare la nuova API InitalizeCriticalSectionEx e passare il flag CRITICAL_SECTION_NO_DEBUG_INFO.
Il vantaggio è che potrebbe essere più veloce poiché, molto spesso, verrà utilizzato solo lo spincount senza dover attendere effettivamente.
Gli svantaggi sono che le vecchie applicazioni possono essere incompatibili, è necessario modificare il codice ed è ora dipendente dalla piattaforma (è necessario verificare la versione per determinare quale utilizzare). E inoltre si perde la possibilità di eseguire il debug se necessario.

kit di test per bloccare Windows Server 2008:
- costruire 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; 
} 

-... eseguire questo file batch (ha bisogno del sonno.exe da 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 vedere un server Win2008 con 8GB e quad core CPU di congelamento prima di raggiungere i 300 casi lanciati.
-... ripetere su un server Windows 2003 e vederlo gestirlo come un incantesimo.

+0

Ciao Francois, grazie per le informazioni. Potresti eventualmente incollare il codice della sezione di inizializzazione di Delphi per utilizzare automaticamente InitializeCriticalSectionEx quando è in esecuzione su Vista/Windows 2008? – carlmon

1

Stai vedendo qualcos'altro.

Ho appena costruito & eseguito questo codice di prova. Ogni statistica di utilizzo della memoria è costante: byte privati, set di lavoro, 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; 
} 
+0

grazie Michael. Hai monitorato la memoria per la tua applicazione quando è avviata e inattiva, mentre esegui il test CS e, dopo averlo fatto, mentre è inattiva e non è ancora terminata. La memoria è sempre completamente ripristinata dopo che l'app è terminata, il problema è quando è ancora attivo dopo aver usato molto il CS. (spero sia chiaro) –

+0

Nota il ciclo infinito (while (true)). L'ho monitorato mentre l'applicazione eseguiva attivamente la creazione e l'eliminazione di sezioni critiche. L'utilizzo della memoria era costante, come previsto. – Michael

+0

Mi aspetto che vada su e giù quando si creano e si eliminano le sezioni critiche che mostrano i denti di taglio belli in Process Explorer (byte privati). A proposito, l'ho fatto con 10.000.000 se fa la differenza. –

2

Probabilmente il test non rappresenta il 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 allo stesso tempo, per sincronizzarli viene effettivamente creato un mutex - e questa è una storia diversa.

presumo nelle vostre discussioni reale app fanno collidere, in contrapposizione al vostro test app. Ora, se stai veramente trattando le sezioni critiche come mutex leggeri e ne crei molti, la tua app potrebbe allocare un gran numero di mutex del kernel reali, che sono molto più pesanti dell'oggetto light critical section. E poiché i mutex sono oggetti del kernel, la creazione di un numero eccessivo di essi può davvero danneggiare il sistema operativo.

Se questo è davvero il caso, si dovrebbe ridurre l'utilizzo di sezioni critiche in cui ci si aspetta un sacco di 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 numero di handle del sistema operativo e osserva come sta andando la tua app.

+0

Il punto principale è che lo stesso codice (semplicemente chiamando l'API) funziona bene su XP/2003 ma non su Vista/2008. –

+0

Non ho idea di come funzioni il codice, ma almeno per un'app di test che assegna e libera in modo ripetitivo la memoria, è possibile che il gestore della memoria stia tentando di memorizzare nella cache la memoria libera anziché restituirla al sistema operativo, supponendo che sarà richiesta presto. Vista e XP hanno probabilmente diversi gestori di memoria, quindi la differenza. Succede lo stesso quando si assegna qualche altra struttura arbitraria con le stesse dimensioni invece del vero CS? Vedete davvero molte maniglie create? – eran

Problemi correlati