Domanda

Nel mio posto in cui lavoro, avevo file con più di milioni di righe per file. Anche se la memoria del server è superiore a 10 GB con 8 GB per JVM, a volte il server viene impiccato per alcuni istanti e soffoca le altre attività.

Ho profilato il codice e ho scoperto che mentre l'uso della memoria di lettura dei file aumenta di frequente in byte Giga (da 1 GB a 3 GB) e poi improvvisamente torna alla normalità. Sembra che questo uso frequente di memoria alta e bassa blocchi i miei server. Ovviamente ciò era dovuto alla raccolta dei rifiuti.

Quale API devo usare per leggere i file per prestazioni migliori?

Adesso sto usando BufferedReader (nuovo FileReader (...)) per leggere questi file CSV.

Processo: come sto leggendo il file?

  1. Ho letto i file riga per riga.
  2. Ogni riga ha poche colonne. in base ai tipi li analizzo di conseguenza (colonna dei costi in doppio, visita la colonna in int, colonna delle parole chiave in String, ecc.).
  3. Invio il contenuto idoneo (visita > 0) in una HashMap e alla fine cancella quella mappa alla fine dell'attività

Aggiorna

Faccio questa lettura di 30 o 31 file (dati di un mese) e memorizzo l'idoneo in una mappa. Successivamente questa mappa viene utilizzata per ottenere alcuni colpevoli in diverse tabelle. Pertanto è indispensabile leggere e archiviare tali dati. Anche se ho passato la parte di HashMap a BerkeleyDB ora, ma il problema al momento della lettura del file è lo stesso o anche peggio.

È stato utile?

Soluzione

BufferedReader è una delle due migliori API da utilizzare per questo. Se hai davvero avuto problemi con la lettura dei file, un'alternativa potrebbe essere quella di usare le cose in NIO per mappare in memoria i tuoi file e quindi leggere i contenuti direttamente dalla memoria.

Ma il tuo problema non è con il lettore. Il tuo problema è che ogni operazione di lettura crea un sacco di nuovi oggetti, molto probabilmente nelle cose che fai subito dopo la lettura.

Dovresti considerare di ripulire il tuo processo di input con un occhio alla riduzione del numero e / o della dimensione degli oggetti che crei, o semplicemente di sbarazzarti degli oggetti più rapidamente quando non sono più necessari. Sarebbe possibile elaborare il tuo file una riga o pezzo alla volta piuttosto che inalare il tutto in memoria per l'elaborazione?

Un'altra possibilità sarebbe quella di giocherellare con la raccolta dei rifiuti. Hai due meccanismi:

  • Chiama esplicitamente il garbage collector ogni tanto, dì ogni 10 secondi o ogni 1000 righe di input o qualcosa del genere. Ciò aumenterà la quantità di lavoro svolto dal GC, ma ci vorrà meno tempo per ciascun GC, la tua memoria non si gonfia tanto e quindi si spera che avrà un impatto minore sul resto del server.

  • Gioca con le opzioni del garbage collector della JVM. Questi differiscono tra JVM, ma java -X dovrebbe darti alcuni suggerimenti.

Aggiornamento: l'approccio più promettente:

Hai davvero bisogno dell'intero set di dati in memoria contemporaneamente per l'elaborazione?

Altri suggerimenti

  

Ho profilato il codice e l'ho trovato   mentre aumenta l'uso della memoria di lettura dei file in   Giga byte frequentemente (da 1 GB a 3 GB) e   poi improvvisamente torna alla normalità. esso   sembra che questo alto e basso frequenti   la memoria usa si blocca i miei server. Di   ovviamente questo era dovuto a Garbage   raccolta.

L'uso di BufferedReader (nuovo FileReader (...)) non lo causerà.

Sospetto che il problema sia che stai leggendo le righe / le righe in un array o in un elenco, le elabori e poi scarti l'array / l'elenco. Ciò causerà un aumento dell'utilizzo della memoria e quindi una nuova riduzione. In tal caso, è possibile ridurre l'utilizzo della memoria elaborando ogni riga / riga durante la lettura.

MODIFICA : siamo d'accordo che il problema riguarda lo spazio utilizzato per rappresentare il contenuto del file in memoria. Un'alternativa a un enorme hashtable in memoria è di tornare al vecchio "merge di ordinamento" approccio che abbiamo usato quando la memoria del computer è stata misurata in Kbyte. (Suppongo che l'elaborazione sia dominata da un passaggio in cui si sta effettuando una ricerca con i tasti K per ottenere la riga associata R.)

  1. Se necessario, preelaborare ciascuno dei file di input in modo che possano essere ordinati sulla chiave K.

  2. Utilizzare un'utilità di ordinamento file efficiente per ordinare tutti i file di input in ordine sul K. Si desidera utilizzare un'utilità che utilizzerà un algoritmo di ordinamento di tipo merge classico. Questo sarà dividere ogni file in blocchi più piccoli che possono essere ordinati in memoria, ordinare i blocchi, scriverli in file temporanei, quindi unire i file temporanei ordinati. L'utilità UNIX / Linux sort è una buona opzione.

  3. Leggi i file ordinati in parallelo, leggendo tutte le righe relative a ciascun valore chiave da tutti i file, elaborandoli e passando al valore chiave successivo.

In realtà, sono un po 'sorpreso che l'uso di BerkeleyDB non abbia aiutato. Tuttavia, se la profilazione ti dice che la maggior parte del tempo è stato dedicato alla creazione del DB, potresti essere in grado di accelerarlo ordinando il file di input (come sopra!) In ordine crescente di chiavi prima di creare il DB. (Quando si crea un indice basato su file di grandi dimensioni, si ottengono prestazioni migliori se le voci vengono aggiunte nell'ordine delle chiavi.)

Prova a usare le seguenti opzioni vm per mettere a punto gc (ed esegui una stampa gc):

-verbose:gc -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top