Domanda

Il nostro servizio tende ad addormentarsi durante le notti sul server del nostro cliente, e quindi a svegliarsi con difficoltà. Ciò che sembra accadere è che l'heap del processo, che a volte è composto da diverse centinaia di MB, viene spostato nel file di scambio. Questo accade di notte, quando il nostro servizio non viene utilizzato e altri sono programmati per l'esecuzione (backup di DB, scansioni AV ecc.). Quando ciò accade, dopo alcune ore di inattività la prima chiamata al servizio impiega fino a pochi minuti (le chiamate successive richiedono pochi secondi).

Sono abbastanza sicuro che si tratti di un problema di gestione della memoria virtuale e odio davvero l'idea di forzare il sistema operativo a mantenere il nostro servizio nella memoria fisica. So che ciò danneggerà altri processi sul server e ridurrà la velocità complessiva del server. Detto questo, i nostri clienti vogliono solo che la nostra app sia reattiva. A loro non importa se i lavori notturni impiegano più tempo.

Ricordo vagamente che c'è un modo per forzare Windows a mantenere le pagine nella memoria fisica, ma odio davvero quell'idea. Mi sto orientando maggiormente verso alcuni watchdog interni o esterni che avvieranno funzionalità di livello superiore (esiste già un programmatore interno che fa molto poco e non fa alcuna differenza). Se esistesse uno strumento di terze parti che fornisse quel tipo di servizio sarebbe stato altrettanto valido.

Mi piacerebbe sentire eventuali commenti, raccomandazioni e soluzioni comuni a questo tipo di problema. Il servizio è scritto in VC2005 e funziona su server Windows.

È stato utile?

Soluzione

Come hai detto, forzare l'app a rimanere in memoria non è il modo migliore per condividere risorse sulla macchina. Una soluzione rapida che potresti trovare che funzioni bene è semplicemente programmare un evento che riattiva il tuo servizio in un momento specifico ogni mattina prima che i tuoi clienti inizino a usarlo. Puoi semplicemente programmarlo nell'utilità di pianificazione di Windows con un semplice script o una chiamata EXE.

Altri suggerimenti

Non sto dicendo che vuoi farlo, o che è la migliore pratica, ma potresti trovare che funzioni abbastanza bene per te. Sembra corrispondere a quello che hai chiesto.

Riepilogo: tocca ogni pagina del processo, alla pagina alla volta, su base regolare.

Che dire di un thread che viene eseguito in background e si sveglia una volta ogni N secondi. Ogni volta che la pagina si sveglia, tenta di leggere l'indirizzo X. Il tentativo è protetto con un gestore di eccezioni nel caso in cui si legga un indirizzo errato. Quindi incrementa X della dimensione di una pagina.

Ci sono 65536 pagine in 4 GB, 49152 pagine in 3 GB, 32768 pagine in 2 GB. Dividi il tuo tempo di inattività (tempo morto durante la notte) per la frequenza con cui vuoi (tentare) di colpire ogni pagina.

BYTE *ptr;

ptr = NULL;
while(TRUE)
{
    __try
    {
        BYTE b;

        b = *ptr;
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        // ignore, some pages won't be accessible
    }

    ptr += sizeofVMPage;

    Sleep(N * 1000);
}

È possibile ottenere il valore sizeOfVMPage dal valore dwPageSize nel risultato restituito da GetSystemInfo ().

Non cercare di evitare il gestore delle eccezioni usando if (! IsBadReadPtr (ptr)) perché altri thread nell'app potrebbero modificare contemporaneamente le protezioni della memoria. Se rimani bloccato a causa di ciò, sarà quasi impossibile identificare il perché (molto probabilmente sarà una condizione di gara non ripetibile), quindi non perdere tempo con esso.

Ovviamente, vorresti disattivare questo thread durante il giorno ed eseguirlo solo durante il tuo tempo morto.

Un terzo approccio potrebbe essere quello di far eseguire al tuo servizio un thread che fa qualcosa di banale come incrementare un contatore e quindi dormire per un periodo abbastanza lungo, diciamo 10 secondi. Questi dovrebbero avere un effetto minimo su altre applicazioni ma mantenere almeno alcune delle tue pagine disponibili.

L'altra cosa da garantire è che i tuoi dati siano localizzati.

In altre parole: hai davvero bisogno di tutti i 300 MiB di memoria prima di poter fare qualcosa? Le strutture di dati utilizzate possono essere riorganizzate in modo tale che una determinata richiesta possa essere soddisfatta con solo pochi megabyte?

Ad esempio

  • se i 300 MiB di memoria heap contengono dati di riconoscimento facciale. I dati possono essere organizzati internamente in modo che i dati dei volti maschili e femminili siano archiviati insieme? O i big noes sono separati dai piccoli nasi?

  • se ha una sorta di struttura logica può essere ordinato? in modo che una ricerca binaria possa essere utilizzata per saltare molte pagine?

  • se si tratta di un motore di database proprietario, in memoria, i dati possono essere meglio indicizzati / raggruppati per non richiedere così tanti hit delle pagine di memoria?

  • se si tratta di trame di immagini, è possibile posizionare le trame comunemente utilizzate una accanto all'altra?

Hai davvero bisogno di tutti i 300 MiB di memoria prima di poter fare qualcosa? Non è possibile soddisfare la richiesta senza tutti i dati in memoria?


Altrimenti: attività pianificata al numero 6 & # 7424; & # 7437; per svegliarlo.

In termini di costi, la soluzione più economica e semplice è probabilmente solo quella di acquistare più RAM per quel server e quindi è possibile disabilitare completamente il file di paging. Se usi Windows a 32 bit, acquista solo 4 GB di RAM. Quindi l'intero spazio degli indirizzi verrà supportato con memoria fisica e il file di paging non farà comunque nulla.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top