2010-06-07 11 views
7

Ho un'applicazione in cui l'intero database è implementato in memoria utilizzando una stl-map per ogni tabella nel database.Come ottimizzare il paging per database di grandi dimensioni in memoria

Ogni elemento nella stl-map è un oggetto complesso con riferimenti ad altri elementi nelle altre mappe stl.

L'applicazione funziona con una grande quantità di dati, quindi utilizza più di 500 MB di RAM. I client sono in grado di contattare l'applicazione e ottenere una versione filtrata dell'intero database. Ciò avviene eseguendo l'intero database e individuando elementi pertinenti per il cliente.

Quando l'applicazione è in esecuzione da un'ora o giù di lì, Windows 2003 SP2 inizia a pagina delle parti della RAM per l'applicazione (anche se sulla macchina è presente una RAM da 16 GByte).

Dopo che l'applicazione è stata parzialmente ignorata, l'accesso al client richiede molto tempo (10 minuti) perché ora genera un errore di pagina per ogni ricerca di puntatori nella mappa stl. Se si esegue l'accesso client una seconda volta subito dopo, è veloce (alcuni secondi) perché tutta la memoria è ora di nuovo nella RAM.

Vedo che è possibile dire a Windows di bloccare la memoria nella RAM, ma in genere è consigliabile solo per i driver di periferica e solo per "piccole" quantità di memoria.

Immagino che una soluzione povera potrebbe essere quella di scorrere l'intero database di memoria, e quindi dire a Windows che siamo ancora interessati a mantenere il datamodel nella RAM.

Immagino che un'altra soluzione povera potrebbe essere disabilitare completamente il file di paging su Windows.

Suppongo che la soluzione costosa sia un database SQL e quindi riscrivi l'intera applicazione per utilizzare un livello di database. Quindi si spera che il sistema di database abbia implementato i mezzi per un accesso rapido.

Ci sono altre soluzioni più eleganti?

+0

L'applicazione viene eseguita come servizio Windows, ma hanno ancora una finestra di console (Usi AllocConsole). Mi chiedo se Windows reagisce a questa finestra della console che viene ridotta a icona, quindi decide di tagliare il working set. –

+0

Si è inoltre notato che molti buffer di lavoro sono stati allocati utilizzando new o malloc ma senza utilizzare una dimensione di blocco uniforme (questa è una vecchia applicazione). Regolando la dimensione dell'allocazione per essere divisibile per 1024, quindi dimezza i byte virtuali per l'applicazione. –

+0

Hanno ora utilizzato ProcDump per registrare le tracce dello stack quando era molto occupato. Ha rivelato che ha trascorso molto tempo su molte grandi nuove operazioni/malloc. Ora ho implementato un migliore riutilizzo del buffer, ma sono ancora perplesso sul motivo per cui il primo accesso al client richiede tempo e la seconda volta è veloce. –

risposta

5

Questo suona come come una perdita di memoria o un grave problema di frammentazione. Mi sembra che il primo passo sarebbe quello di capire che cosa sta causando 500 Mb di dati per utilizzare fino a 16 Gb di RAM e vogliono ancora di più.

Modifica: Windows ha un trimmer di impostazione funzionante che tenta attivamente di escludere i dati inattivi. L'idea di base è che passa attraverso e segna le pagine come disponibili, ma lascia i dati al loro interno (e il gestore della memoria virtuale sa quali sono i dati in esse contenuti). Se, tuttavia, si tenta di accedere a quella memoria prima che venga assegnata ad altri scopi, verrà contrassegnata come di nuovo in uso, il che normalmente impedirà che venga interrotta.

Se si pensa veramente che questa sia la fonte del problema, è possibile controllare indirettamente il trimmer di lavoro chiamando il numero SetProcessWorkingSetSize. Almeno nella mia esperienza, questo è raramente di grande utilità, ma potresti trovarti in una di quelle situazioni insolite in cui è davvero utile.

+0

Sono d'accordo - sembra una perdita per me. Hai provato a usare Valgrind? –

+0

Non riesco a trovare dove dice che ha solo 500 MB di dati che utilizzano 16 GB di RAM. D'altra parte, anche io non capisco perché l'OP reindirizza esplicitamente a 500 MB di RAM. Ad ogni modo, sono d'accordo con l'idea della perdita di memoria. – PeterK

+0

@PeterK: beh, dice "oltre 500MByte", che presumo significhi solo poco più di 500 MByte. In ogni caso, sembra che sia abbastanza veloce per iniziare, ma alla fine utilizza una memoria sufficiente per iniziare il thrashing ... –

0

---- Edit

Dato snakefoot spiegazione, il problema è sostituendo memoria che non viene utilizzato per un lungo periodo di tempo e per questo non avere i dati nella memoria quando necessario.Questo è lo stesso di questo:

Can I tell Windows not to swap out a particular processes’ memory?

e la funzione VirtualLock dovrebbe fare il suo lavoro:

http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx

---- Risposta precedente

Prima di tutto è necessario distinguere tra perdita di memoria e problemi di memoria.

Se si dispone di una perdita di memoria, sarebbe più difficile convertire l'intera applicazione in SQL piuttosto che eseguire il debug dell'applicazione.

SQL non può essere più veloce di un database in memoria ben progettato e specifico del dominio e se si hanno dei bug, è probabile che ne avrete di diversi anche in una versione SQL.

Se si tratta di un problema di memoria, è necessario passare a SQL in ogni caso e questo sembra un buon momento.

+0

Non penso che ci siano problemi di perdita di memoria, dal momento che l'applicazione non utilizza più RAM nel tempo. Semplicemente non tocca costantemente tutta la memoria allocata, quindi il gestore di memoria di Windows 2003 pensa che sia corretto sfogliare la memoria. Il Memory Manager di Windows 2003 salva la memoria anche se c'è molta memoria nella macchina. –

+0

Sono d'accordo su snakefoot, in teoria la memoria dovrebbe essere solo specchiata * al file di paging, fino a quando non ha davvero bisogno di essere spremuta. Ma può sembrare di essere riallocato molto prima che sia necessario. – strainer

+0

Non sono sicuro di volere il comportamento di Virtual Lock, poiché impedisce a Windows di eseguire il paging dell'applicazione, anche se la memoria è necessaria per situazioni critiche. Preferirei preferire una soluzione in cui si potrebbe dire a Windows di non essere così aggressivo riguardo la mia applicazione. –

2

Come ha detto @Jerry Coffin, sembra proprio che il tuo problema sia una perdita di memoria. Correggilo.

Ma per la cronaca, nessuna delle vostre "soluzioni povere" funzionerebbe. Affatto.

Le pagine di Windows fuori alcuni dei tuoi dati perché non c'è spazio nella RAM. Il ciclo di caricamento dell'intero database di memoria verrebbe caricato in ogni byte del modello di dati, sì ... il che causerebbe il blocco di altre parti di esso. Alla fine, si genererebbero molti errori di pagina e l'unica differenza alla fine sarebbe che le parti della struttura dei dati sono state spostate all'esterno della struttura dati.

Disabilitare il file di paging? Sì, se pensi che un crash duro sia meglio delle basse prestazioni. Windows non esegue il page out dei dati perché è divertente. Lo fa per gestire situazioni in cui altrimenti finirebbe a corto di memoria. Se disattivi il file di paging, l'app si arresta in modo anomalo quando altrimenti pubblicherebbe i dati.

Se il set di dati è davvero così grande, non si adatta alla memoria, quindi non vedo perché un database SQL sarebbe particolarmente "costoso". A differenza della tua attuale soluzione, i database sono ottimizzati per questo scopo. Sono pensati per gestire dataset troppo grandi per adattarsi alla memoria e per farlo in modo efficiente.

Sembra che tu abbia una perdita di memoria. Fissaggio che sarebbe la soluzione elegante, efficiente e corretta.

Se non è possibile farlo, allora o

  • tiro più RAM al problema (l'applicazione finisce con 16GB? Gettare 32 o 64GB in poi), o
  • passaggio a un formato ottimizzato per un accesso efficiente al disco (probabilmente un database SQL)
+0

Anche in questo caso l'applicazione utilizza solo 500 MByte RAM quando si utilizza Task Manager. Il problema è come l'algoritmo di paging di Windows sta scambiando l'applicazione anche se c'è abbastanza RAM. –

+0

@snakefoot: no. Windows non lo fa. E Task Manager non è un modo affidabile per determinare l'utilizzo della memoria. – jalf

+1

Avete mai avuto un computer con Windows XP, lasciato inutilizzato per diverse ore, e quindi si inizia a usarlo. I primi minuti tutto è piuttosto lento perché il gestore della memoria ha cancellato la maggior parte della memoria. Voglio incoraggiare Windows a mantenere la mia applicazione in memoria. –

0

Abbiamo un problema simile e la soluzione che scegliamo era allocare tutto in un blocco di memoria condiviso. AFAIK, Windows non lo presenta. Tuttavia, l'uso di stl-map qui non è per debole di cuore ed era oltre ciò che avevamo richiesto.

Stiamo usando Boost Shared Memory per implementare questo per noi e funziona bene.Segui gli esempi da vicino e sarai subito operativo. Boost ha anche Boost.MultiIndex che farà molto di quello che vuoi.

Per una soluzione sql gratuita avete visto Sqlite? Hanno un'opzione da eseguire come un database in memoria.

Buona fortuna, sembra un'applicazione interessante.

+0

In realtà, i vantaggi di non dover eseguire la mappatura su un livello di database offrono davvero molta libertà. Eseguiamo la serializzazione su XML solo quando è necessario persistenza. L'utilizzo di XML semplifica l'integrazione con altre applicazioni in quanto è possibile utilizzare i fogli di stile durante l'importazione/esportazione. –

+0

@snakefoot - Sono pienamente d'accordo con point on db. Stavo suggerendo SQLite solo perché era facile renderlo in-memory db. –

0

Ho un'applicazione in cui l'intero database è implementata in memoria utilizzando uno STL-map per ogni tabella nel database .

Questo è l'inizio della fine: STL's std :: map è estremamente inefficiente. Lo stesso vale per std :: list. Ogni elemento sarebbe assegnato separatamente causando uno spreco di memoria piuttosto serio. Io uso spesso std :: vector + sort() + find() invece di std :: map in applicazioni dove è possibile (più ricerche che modifiche) e so che l'utilizzo della memoria in anticipo potrebbe diventare un problema.

Quando l'applicazione è gestito per un'ora o giù di lì, quindi Windows 2003 SP2 inizia a pagina in parti del RAM per l'applicazione (Eventhough c'è 16 GByte di RAM sulla macchina).

Difficile dire, senza sapere come è scritta la tua domanda. Windows ha la funzione di scaricare dalla RAM qualsiasi memoria delle applicazioni inattive può essere scaricata. Ma questo normalmente interessa i file mappati in memoria e allo stesso modo.

In caso contrario, suggerisco vivamente di leggere Windows memory management documentation. Non è molto facile da capire, eppure Windows ha tutti i tipi e tipi di memoria disponibili per le applicazioni. Non ho mai avuto fortuna con esso, ma probabilmente nella tua applicazione usando lo std :: allocator personalizzato funzionerebbe.

+0

Il problema sarebbe scrivere un allocatore STL per questi altri tipi di memoria. Insieme al fatto che la memoria non paginata è una risorsa limitata. Voglio solo incoraggiare Windows a mantenere la mia applicazione in memoria invece di impaginarla. –

+0

"Insieme al fatto che la memoria non paginata è una risorsa limitata." Bene, se sai esattamente quali applicazioni verranno eseguite sul server e quali sono le loro esigenze di memoria, allora è perfettamente OK utilizzare anche la memoria non di paging. In questo modo si ruba il sistema operativo dalla RAM fisica ciò che è generalmente considerato negativo. Ma se l'attività richiede che lo spazio di archiviazione sia nella RAM per un accesso rapido garantito, allora c'è poca scelta. – Dummy00001

0

Posso credere che sia colpa del comportamento del file di paging errato: ho eseguito i miei laptop principalmente con il file di paging disattivato da nt4.0. Nella mia esperienza, almeno fino a XP Pro, Windows scambia in modo intrusivo le pagine solo per fornire il discutibile vantaggio di avere un'estensione davvero molto lenta al massimo spazio di lavoro.

Chiedi quale vantaggio si ottiene scambiando su harddisk con 16 gigabity di RAM reale disponibili? Se il tuo lavoro lo rende così grande da richiedere più memoria virtuale di +10 Gigs, allora una volta che lo swap è necessario, i processi richiederanno qualcosa di un po 'più lungo, a migliaia di volte più lungo da completare. Su Windows, la cache del file system non è rimovibile sembra antagonizzare le relazioni.

Ora, quando (molto) di tanto in tanto non funziona più sui miei laptop XP, non c'è traffico, l'app colpevole si blocca. Un'utilità per sospendere i processi di glugging della memoria prima di quel momento e fare un avviso sarebbe bello, ma non esiste una cosa del genere solo una violazione, un crash e talvolta anche explorer.exe va giù.

pagefiles - chi ha bisogno di em'

+0

Bene, il file di paging e l'alogoritm di paging sono stati inventati al momento in cui i computer avevano solo 16 MB di RAM, molte applicazioni dipendono da questo comportamento e probabilmente si interrompono se vengono cambiate. Credo che Microsoft abbia cambiato le cose con Windows 2008, quindi in realtà cerca di massimizzare l'uso della memoria. Ma in questo momento stiamo usando Windows 2003 SP2. –