Pregunta

Parece que el uso de las secciones críticas bastante en Vista / Windows Server 2008 hace que el sistema operativo no recupere completamente la memoria. Encontramos este problema con una aplicación Delphi y es claramente debido al uso de la API de CS. (vea esto SO pregunta )

¿Alguien más lo ha visto con aplicaciones desarrolladas con otros lenguajes (C ++, ...)?

El código de muestra solo estaba inicializando 10000000 CS y luego los eliminó. Esto funciona bien en XP / Win2003 pero no libera toda la memoria pico en Vista / Win2008 hasta que la aplicación haya finalizado.
Cuanto más use CS, más retendrá su aplicación la memoria para nada.

¿Fue útil?

Solución

De hecho, Microsoft ha cambiado la forma en que InitializeCriticalSection funciona en Vista, Windows Server 2008 y probablemente también en Windows 7.
Añadieron una " característica " para conservar algo de memoria utilizada para la información de depuración cuando asigna un montón de CS. Cuanto más se asigna, más memoria se conserva. Puede ser asintótico y eventualmente aplanarse (no comprado completamente a este).
Para evitar esta " característica " ;, tienes que usar la nueva API InitalizeCriticalSectionEx y pase el indicador CRITICAL_SECTION_NO_DEBUG_INFO .
La ventaja de esto es que puede ser más rápido ya que, muy a menudo, solo se utilizará el Spincount sin tener que esperar realmente.
Las desventajas son que sus aplicaciones antiguas pueden ser incompatibles , necesita cambiar su código y ahora depende de la plataforma (debe verificar la versión para determinar cuál usar). Y también pierdes la capacidad de depurar si lo necesitas.

Kit de prueba para congelar un Windows Server 2008:
- compile este ejemplo de 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; 
}

-... Ejecute este archivo por lotes (necesita el sleep.exe del servidor SDK)

@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

-... y vea un servidor Win2008 con 8GB y cuatro núcleos de CPU congelados antes de llegar a las 300 instancias lanzadas.
-... repita en un servidor Windows 2003 y véalo manejarlo como un encanto.

Otros consejos

Lo más probable es que su prueba no sea representativa del problema. Las secciones críticas se consideran "mutexes de peso ligero" porque no se crea un mutex real del núcleo al inicializar la sección crítica. Esto significa que sus 10M secciones críticas son solo estructuras con unos pocos miembros simples. Sin embargo, cuando dos subprocesos acceden a un CS al mismo tiempo, para sincronizarlos se crea un mutex, y eso es otra historia.

Supongo que en tus hilos de aplicaciones reales chocan, a diferencia de tu aplicación de prueba. Ahora, si realmente está tratando las secciones críticas como mutexs ligeros y crea muchas, su aplicación podría estar asignando una gran cantidad de mutex del núcleo real, que son mucho más pesados ??que el objeto de la sección crítica ligera. Y dado que las mutexes son un objeto del núcleo, crear un número excesivo de ellas realmente puede dañar el sistema operativo.

Si este es el caso, debe reducir el uso de secciones críticas en las que espera muchas colisiones. Esto no tiene nada que ver con la versión de Windows, por lo que mi conjetura podría estar equivocada, pero todavía es algo a tener en cuenta. Intente monitorear el conteo de mangos del sistema operativo y vea cómo está funcionando su aplicación.

Estás viendo algo más.

Acabo de construir & amp; Ejecutó este código de prueba. Cada estadística de uso de memoria es constante: bytes privados, conjunto de trabajo, confirmación, 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top