5

Parece que el uso de 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 question)Secciones críticas que pierden memoria en Vista/Win2008?

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

El código de ejemplo recién inicializaba 10000000 CS, luego los borró. Esto funciona bien en XP/Win2003 pero no libera toda la memoria pico en Vista/Win2008 hasta que la aplicación ha finalizado.
Cuanto más utilice CS, más conservará la memoria su aplicación en vano.

+0

Hola, François. ¿Tienes alguna noticia sobre este tema? Tengo curiosidad :) – Alex

+0

Ver mi propia respuesta. De hecho, hubo un cambio, en la categoría "es-una-función-no-un-error" ... –

+0

Hola, François. Gracias por compartir. Por cierto, puede aceptar su propia respuesta;) – Alex

Respuesta

7

Microsoft ciertamente han cambiado la forma InitializeCriticalSection obras en Vista, Windows Server 2008, y probablemente también en Windows 7.
Se añadió una "característica" de retener parte de la memoria utilizada para la información de depuración cuando se asigna un grupo de CS. Cuanto más asigna, más memoria se conserva. Puede ser asintótico y finalmente aplanarse (no completamente comprado a este).
Para evitar esta "característica", debe usar la nueva API InitalizeCriticalSectionEx y pasar la bandera CRITICAL_SECTION_NO_DEBUG_INFO.
La ventaja de esto es que podría ser más rápido ya que, muy a menudo, solo se utilizará el contador de vueltas sin tener que esperar.
Las desventajas son que sus aplicaciones anteriores 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 servidor Windows 2008:
- construir este ejemplo 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; 
} 

-... ejecutar este archivo por lotes (necesita el sueño.exe de 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 

-... y ver un servidor Win2008 con 8 GB y de cuatro núcleos CPU de congelación antes de llegar a los 300 casos lanzados.
-... repetir en un servidor de Windows 2003 y verlo manejarlo como un amuleto.

+0

Hola Francois, gracias por la información. ¿Podría pegar su código de sección de inicialización de Delphi para usar automáticamente InitializeCriticalSectionEx cuando se ejecuta en Vista/Windows2008? – carlmon

1

Estás viendo algo más.

Acabo de construir & ejecuté este código de prueba. Cada estadística de uso de memoria es constante: bytes privados, conjunto de trabajo, compromiso, 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; 
} 
+0

gracias Michael. ¿Supervisó la memoria de su aplicación cuando se inició y está inactiva, mientras se ejecutaba la prueba CS y, después de hacerlo, mientras estaba inactiva y aún no terminaba? La memoria siempre se recupera completamente después de que la aplicación ha finalizado, el problema es cuando todavía está activa después de haber usado mucho el CS. (espero que esté claro) –

+0

Tenga en cuenta el ciclo infinito (while (true)). Lo supervisé mientras la aplicación se ejecutaba activamente creando y eliminando secciones críticas. El uso de memoria fue constante, como se esperaba. – Michael

+0

Esperaría que suba y baje cuando crea y elimina las secciones críticas que muestran dientes de sierra bonitos en Process Explorer (bytes privados). Por cierto, lo hice con 10,000,000 si hace la diferencia. –

2

Probablemente su examen no es representativo del problema. Las secciones críticas se consideran "mutexes livianas" porque no se crea un mutex de kernel real al inicializar la sección crítica. Esto significa que sus secciones críticas de 10M son solo estructuras con unos pocos miembros simples. Sin embargo, cuando dos subprocesos acceden a una CS al mismo tiempo, para sincronizarlos se crea un mutex, y esa es una historia diferente.

Supongo que en su aplicación real los hilos chocan, a diferencia de su aplicación de prueba. Ahora, si realmente está tratando las secciones críticas como mutexes livianos y las crea muchas, su aplicación podría estar asignando una gran cantidad de mutexes de kernel reales, que son mucho más pesados ​​que el objeto de sección crítico de luz. Y dado que mutexes son un objeto kernel, la creación de un número excesivo de ellos realmente puede dañar el sistema operativo.

Si este es realmente el caso, debe reducir el uso de las secciones críticas donde se esperan muchas colisiones. Esto no tiene nada que ver con la versión de Windows, así que supongo que podría estar equivocado, pero aún es algo a considerar. Intente controlar el conteo de los controladores del sistema operativo y vea cómo le va a su aplicación.

+0

El punto principal es que el mismo código (simplemente llamando a la API) funciona bien en XP/2003 pero no en Vista/2008. –

+0

No tengo idea de cómo funciona su código, pero al menos para una aplicación de prueba que asigna y libera memoria de manera repetitiva, es posible que el administrador de memoria intente almacenar en memoria caché la memoria en lugar de devolverla al sistema operativo, suponiendo que será necesaria. pronto. Vista y XP probablemente tienen diferentes administradores de memoria, de ahí la diferencia. ¿Ocurre lo mismo al asignar alguna otra estructura arbitraria con el mismo tamaño en lugar de CS real? ¿De verdad ves que se crean muchos mangos? – eran

Cuestiones relacionadas