Pergunta

Parece que o uso de seções críticas um pouco no Vista / Windows Server 2008 leads para o sistema operacional não recuperar totalmente a memória. Encontramos este problema com uma aplicação Delphi e é claramente por causa de usar a API CS. (Ver esta pergunta )

Tem mais alguém visto com aplicações desenvolvidas com outras linguagens (C ++, ...)?

O código de exemplo foi apenas initialzing 10000000 CS, em seguida, excluí-los. Esta multa funciona em XP / Win2003 mas não liberar toda a memória de pico no Vista / Win2008 até que a aplicação foi encerrada.
Quanto mais você usa CS, mais a sua aplicação mantém memória para nada.

Foi útil?

Solução

Microsoft realmente mudaram as obras maneira InitializeCriticalSection no Vista, Windows Server 2008, e provavelmente também o Windows 7.
Eles acrescentaram um "recurso" para manter alguma memória usada para obter informações de depuração quando você alocar um monte de CS. Quanto mais você alocar, mais memória é mantido. Pode ser assintótica e, eventualmente, achatar (não totalmente comprado para este).
Para evitar este "recurso", você tem que usar a nova API InitalizeCriticalSectionEx e passar o CRITICAL_SECTION_NO_DEBUG_INFO bandeira.
A vantagem disso é que ele pode ser mais rápido que, muitas vezes, apenas o spincount será usado sem ter que esperar.
As desvantagens são que seus aplicativos antigos podem ser incompatíveis , você precisa alterar o código e agora é dependente de plataforma (você tem que verificar para a versão para determinar qual deles usar). E também você perder a capacidade de depuração se você precisar.

kit de teste para congelar um Windows Server 2008:
- construir este exemplo C ++ como 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; 
}

-... Executar este arquivo de lote (precisa do Sleep.exe do SDK servidor)

@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 ver um servidor Win2008 com 8GB e quad core CPU congelamento antes de atingir os 300 casos lançados.
-... repetição em um servidor Windows 2003 e vê-lo lidar com isso como um encanto.

Outras dicas

Seu teste é, provavelmente, não é representativo do problema. As seções críticas são considerados "mutexes leve" porque um mutex do kernel real não é criado quando você inicializar a seção crítica. Isso significa que suas seções 10M crítica são apenas estruturas com alguns membros simples. No entanto, quando dois threads acessar um CS, ao mesmo tempo, a fim de sincronizá-los um mutex é realmente criado. - E isso é uma história diferente

Eu assumo em seus segmentos de aplicativos reais que colidem, ao contrário de seu aplicativo de teste. Agora, se você está realmente tratar seções críticas como mutexes leves e criar um monte deles, a sua aplicação pode ser atribuição de um grande número de semáforos do kernel reais, que são muito mais pesado do que a luz objeto seção crítica. E desde mutexes são objeto de kernel, criando um número excessivo deles pode realmente prejudicar o OS.

Se este for realmente o caso, você deve reduzir o uso de seções críticas onde você espera um monte de colisões. Isto não tem nada a ver com a versão do Windows, então o meu palpite pode estar errado, mas ainda é algo a considerar. Tente monitorar o OS contar alças, e ver como seu aplicativo está fazendo.

Você está vendo outra coisa.

Eu só construiu e correu este código de teste. Todas as estatísticas de uso de memória é constante -. Bytes particulares, conjunto de trabalho, cometer, e assim por diante

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top