2013-05-09 5 views
5

Ho scritto un piccolo programma java che carica i dati dal database DB2 utilizzando una semplice chiamata JDBC. Sto usando una query di selezione per ottenere dati e usando l'istruzione java per questo scopo. Ho degli oggetti di istruzione e connessione correttamente chiusi. Sto usando JVM a 64 bit per la compilazione e per l'esecuzione del programma.Perché la mia chiamata JDBC sta consumando memoria 4 volte di più delle dimensioni effettive dei dati

La query restituisce 52 milioni di record, ogni riga con 24 colonne, che richiede circa 4 minuti per caricare i dati completi in Unix (con ambiente multiprocessore). Sto usando HashMap come struttura dati per caricare i dati: Map<String, Map<String, GridTradeStatus>>. Il bean GridTradeStatus è un semplice bean getter/setter con 24 proprietà.

La memoria richiesta per il programma è allarmante. Le dimensioni dell'heap Java aumentano fino a 5,8 - 6 GB per caricare i dati completi mentre la dimensione effettiva dell'heap utilizzata rimane tra 4,7 - 4,9 GB. So che non dovremmo caricare tanti dati in memoria, ma i miei requisiti aziendali sono solo in questo modo.

La domanda è che quando inserisco interi dati del mio tavolo in un file flat risulta essere approssimativamente equivalente a ~ 1,2 GB. Voglio sapere perché il mio programma java sta consumando memoria 4 volte di più delle sue dimensioni reali.

+0

Le stringhe in java utilizzano UTF-16, che significa 2 byte per ogni carattere. In questo modo si duplica l'utilizzo della ram se il file txt è una normale codifica a 8 bit/char. Inoltre, se si utilizza il metodo substring, ricordare che la stringa originale newer viene liberata, purché l'oggetto substring sia attivo. – MTilsted

+0

Grazie per il tuo commento. È in qualche modo possibile indirizzare JVM all'uso della codifica UTF-8? –

+0

Non direttamente. java.lang.String userà sempre UTF-16. Ma sono sicuro che una ricerca su google può darti una classe di stringa java, che usa utf-8 o un'altra codifica a 8 bit. – MTilsted

risposta

0

Qui non c'è nulla di sorprendente (almeno per me).

a.) Le stringhe in java consumano il doppio dello spazio rispetto ai formati di testo più comuni (poiché le stringhe sono sempre rappresentate come UTF-16 nell'heap). Inoltre, String come oggetto ha un certo overhead (oggetto String stesso, riferimento al char [] che contiene, hashCode ecc.). Per le stringhe piccole, l'oggetto String costa facilmente tanta memoria quanto i dati che contiene.

b.) Si inserisce materiale in una HashMap. HashMap non è esattamente efficiente in termini di memoria. Innanzitutto utilizza un fattore di carico predefinito del 75%, il che significa che una mappa con molte voci ha anche un grande array di bucket. Quindi, ogni voce nella mappa è un oggetto stesso, che costa almeno due riferimenti (chiave e valore) oltre all'overhead dell'oggetto.

In conclusione è necessario prevedere i requisiti di memoria per aumentare un po '. Un fattore 4 è ragionevole se la stringa di dati media è relativamente breve.

0

Se pensate di non potervi permettere un rapporto 1: 4 tra la dimensione dei dati in un file piatto e la memoria necessaria per caricare le stringhe in una HashMap, non dovreste usare Java ma un linguaggio di livello inferiore come C++ o anche C.

Naturalmente ci sono possibili ottimizzazioni:

  • uso byte[] anziché String (circa la metà)
  • non usano predefinito HashMap parametri (dimensione iniziale/fattore di carico) ma ritoccare la calibrazione loro per incontrarti r requisiti reali.

Quello che segue è principalmente esperienza basato sull'opinione. Uso generalmente 4 livelli di lingua:

  • linguaggio di scripting di alto livello (Python, Ruby o anche bash ...) quando la prestazione non è un requisito e la velocità di sviluppo è
  • linguaggio di medio livello (Java, C++ di livello più basso frequentemente quando le prestazioni sono importanti ma quando voglio anche semplicità di sviluppo e robustezza (forte tipizzazione, ...)
  • basso linguaggio di livello (basso livello di C++ o C) ciò che le prestazioni è un requisito elevato e quando accetto di passare molto più tempo nella scrittura e testare i singoli moduli
  • lingua
  • assembly per le piccole parti in cui le prestazioni è critico e è stato dimostrato di essere profilatura.

IMHO è possibile modificare il codice Java per ridurre notevolmente l'ingombro della memoria, ma si rischia di perdere gran parte dell'interesse di Java perdendo l'eccellente supporto per stringhe e raccolte. Potrebbe essere facile e forse più efficiente codificare una piccola parte dell'applicazione in C++ e usare JNI per legare tutti insieme.

Problemi correlati