2009-05-07 17 views
6

Il nostro servizio tende ad addormentarsi durante le notti sul server del nostro cliente, e quindi ha difficoltà a svegliarsi. Ciò che sembra accadere è che l'heap del processo, che a volte è di diverse centinaia di MB, viene spostato nel file di swap. Ciò accade di notte, quando il nostro servizio non viene utilizzato e altri sono programmati per essere eseguiti (backup di database, scansioni AV, ecc.). In questo caso, dopo alcune ore di inattività, la prima chiamata al servizio richiede alcuni minuti (le chiamate successive richiedono alcuni secondi).Prevenire un processo pesante dall'affondamento nel file di scambio

Sono quasi certo che si tratta 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 farlo danneggerà altri processi sul server e ridurrà il throughput generale del server. Detto questo, i nostri clienti vogliono solo che la nostra app sia reattiva. A loro non importa se i lavori notturni richiedono più tempo.

Ricordo vagamente che c'è un modo per forzare Windows a mantenere le pagine nella memoria fisica, ma io odio davvero quell'idea. Mi sto appoggiando più verso un watchdog interno o esterno che avvierà funzionalità di livello superiore (c'è già un programmatore interno che fa pochissimo, e non fa differenza). Se ci fosse uno strumento di terze parti che ha fornito quel tipo di servizio sarebbe stato altrettanto buono.

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

risposta

8

Come hai detto, forzare l'app a rimanere in memoria non è il modo migliore per condividere le risorse sulla macchina. Una soluzione rapida che potresti trovare che funziona bene è semplicemente pianificare 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.

0

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

+0

Questo sarebbe vero se solo il mio servizio fosse in esecuzione sul server. Tuttavia, gestisce anche un server Web, un database, un antivirus e altri servizi. Per eliminare la necessità del file di pagina saranno necessari 4 GB per ogni processo, non è vero? Detto questo, aggiungere più RAM è una buona soluzione, ma dipende dal cliente, e sto cercando un lavoro di sviluppo che non costringa molti clienti a spendere di più. – eran

+0

"Per eliminare la necessità del file di pagina saranno necessari 4 GB per ogni processo, no?" Non come capisco. Per Windows a 32 bit, 4 GB rappresentano il totale complessivo di tutto e sei fortunato se ottieni tutti e quattro i gigabyte. Questa macchina, ad esempio, ha 4 GB di memoria fisica ma solo 2,75 GB sono disponibili per i programmi, dal momento che altre cose mangiano lo spazio degli indirizzi. – kquinn

+1

Ma ogni processo ottiene il suo/proprio/4GB di spazio di indirizzamento (senza contare quello che prende il kernel), quindi se hai 30 processi ognuno di loro potrebbe usare 1GB di RAM e avere solo la maggior parte di esso scambiati, nel qual caso tu sei ancora è necessario un file di paging ... –

1

Un terzo approccio potrebbe essere quello di fare in modo che il servizio esegua un thread che faccia qualcosa di banale come incrementare un contatore e poi dorme per un periodo piuttosto lungo, diciamo 10 secondi. Thios dovrebbe avere un effetto minimo su altre applicazioni, ma mantenere almeno alcune delle tue pagine disponibili.

+0

Penso che questo manterrà le pagine che contengono questo pezzo di codice in memoria, ma l'heap sarà ancora scambiato. Dal momento che molto più memoria viene utilizzata dall'heap, il problema è probabilmente da parte sua. Potrei camminare sul mucchio invece di incrementare il contatore, ma questo non avrebbe avuto un effetto minimo ... – eran

2

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

Riepilogo: Toccare ogni pagina nel processo, su una 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 risveglia, tenta di leggere dall'indirizzo X. Il tentativo è protetto con un gestore di eccezioni nel caso in cui si legga un indirizzo errato. Quindi incrementa X in base alla 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) della frequenza con cui desideri (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 tentare di evitare il gestore di eccezioni utilizzando if (!IsBadReadPtr (ptr)) perché altri thread nell'app potrebbero modificare le protezioni della memoria contemporaneamente. Se ti sblocchi a causa di questo, sarà quasi impossibile identificare il perché (sarà molto probabilmente una condizione di gara non ripetibile), quindi non perdere tempo con esso.

Ovviamente, vorresti spegnere questo thread durante il giorno e farlo funzionare solo durante il tuo tempo morto.

1

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

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

Per esempio

  • se il 300 Mb di memoria heap contiene i dati di riconoscimento facciale. I dati possono essere sistemati internamente in modo tale che i dati di volti maschili e femminili siano memorizzati insieme? O i big-no sono separati dai piccoli nasi?

  • se ha qualche tipo di struttura logica può essere ordinato? in modo che una ricerca binaria può essere utilizzata per saltare un sacco di pagine?

  • se si tratta di un motore di database propritary, in memoria, i dati possono essere meglio indicizzati/raggruppati in modo da non richiedere così tanti clic sulla memoria?

  • se sono trame delle immagini, le trame comunemente utilizzate possono essere posizionate l'una vicino all'altra?

Hai davvero bisogno di tutti i 300 MiB della memoria prima di poter fare qualcosa? Non è possibile richiedere assistenza senza tutti i dati che i dati tornano in memoria?


Altrimenti: un'operazione pianificata a 6 ᴀᴍ per riattivarlo.