Question

Il semble que l'utilisation assez fréquente de sections critiques dans Vista / Windows Server 2008 empêche le système d'exploitation de récupérer complètement la mémoire. Nous avons trouvé ce problème avec une application Delphi et c'est clairement dû à l'utilisation de l'API CS. (voir ce SO question )

Quelqu'un d'autre l'a-t-il vu avec des applications développées avec d'autres langages (C ++, ...)?

L'exemple de code initialisait 10000000 CS, puis les supprimait. Cela fonctionne bien sous XP / Win2003 mais ne libère pas toute la mémoire de pointe sous Vista / Win2008 avant la fin de l'application.
Plus vous utilisez CS, plus votre application conserve de la mémoire pour rien.

Était-ce utile?

La solution

Microsoft a en effet changé le fonctionnement de InitializeCriticalSection sur Vista, Windows Server 2008 et probablement aussi Windows 7.
Ils ont ajouté une "fonctionnalité". conserver une partie de la mémoire utilisée pour les informations de débogage lorsque vous allouez un groupe de CS. Plus vous allouez, plus la mémoire est conservée. Il pourrait être asymptotique et éventuellement aplati (pas complètement acheté à celui-ci).
Pour éviter cette "fonctionnalité", vous devez utiliser la nouvelle API InitalizeCriticalSectionEx et transmettez le drapeau CRITICAL_SECTION_NO_DEBUG_INFO .
L'avantage de cela est que cela pourrait être plus rapide, car très souvent, seul le spincount sera utilisé sans avoir à attendre réellement.
L’inconvénient est que vos anciennes applications peuvent être incompatibles , vous devez modifier votre code et celui-ci dépend désormais de la plate-forme (vous devez vérifier la version pour déterminer celle à utiliser). Et vous perdez également la possibilité de déboguer si vous en avez besoin.

Kit de test pour figer un serveur Windows Server 2008:

- Construisez cet exemple C ++ en tant que 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; 
}

-... Exécuter ce fichier de commandes (nécessite le fichier sleep.exe du SDK du serveur)

@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

-... et observez un serveur Win2008 gelé par 8 Go et quatre processeurs avant d'atteindre les 300 instances lancées.
-... répéter sur un serveur Windows 2003 et le voir le gérer comme un charme.

Autres conseils

Votre test n'est probablement pas représentatif du problème. Les sections critiques sont considérées comme des "mutex légers". car un véritable mutex de noyau n'est pas créé lorsque vous initialisez la section critique. Cela signifie que vos sections critiques 10M ne sont que des structures composées de quelques membres simples. Cependant, lorsque deux threads accèdent à un CS en même temps, un mutex est effectivement créé pour les synchroniser - et c'est une autre histoire.

Je suppose que dans votre application réelle, les threads se heurtent, contrairement à votre application de test. Désormais, si vous traitez réellement des sections critiques comme des mutex légers et en créez beaucoup, votre application peut allouer un grand nombre de mutex du noyau réel, qui sont bien plus lourds que l'objet section critique. Et comme les mutex sont des objets du noyau, en créer un nombre excessif peut vraiment nuire au système d'exploitation.

Si tel est effectivement le cas, vous devez réduire l'utilisation des sections critiques pour lesquelles vous prévoyez de nombreuses collisions. Cela n’a rien à voir avec la version Windows, alors j’imagine peut-être que je me trompe, mais c’est toujours une chose à considérer. Essayez de surveiller le nombre de poignées de système d’exploitation et voyez comment se porte votre application.

Vous voyez autre chose.

Je viens de construire & amp; a lancé ce code de test. Chaque statistique d'utilisation de la mémoire est constante: octets privés, jeu de travail, validation, etc.

.

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top