2012-04-10 8 views
5

Ho un programma Java che prepara i dati in una struttura di dati piuttosto complessa e grande in memoria (diversi GB) e li serializza su disco, e un altro programma che legge in memoria la struttura di dati serializzata. Sono stato sorpreso di notare che il passo di deserializzazione è piuttosto lento e che è legato alla CPU. (100% di utilizzo della CPU in top ma solo da 3 a 5 MB/s letti con iotop, che è molto basso per quelle che dovrebbero essere le letture sequenziali su un disco rigido). La CPU è abbastanza recente (Core i7-3820), la struttura si adatta alla memoria, nessuno spazio di swap è configurato.Perché la deserializzazione di Java è legata alla CPU?

Perché è così? Esiste un modo alternativo per serializzare oggetti in Java che non ha la CPU come collo di bottiglia?

Ecco il codice di deserializzazione, nel caso in cui è importante:

FileInputStream f = new FileInputStream(path); 
ObjectInputStream of = new ObjectInputStream(f); 
Object obj = of.readObject(); 
+1

IIRC utilizza magico riflesso paragonabile al modo in cui il lavoro .NET serializzatori. È lento. Esiste un concetto concettualmente semplice, ma "molto digitato", per evitare tutto questo: fallo a mano. Cioè, scrivere oggetti ricorsivamente, campo per campo, su un flusso binario. E il contrario per il caricamento. – harold

+1

Questo potrebbe aiutare: http://vanillajava.blogspot.co.uk/2011/10/serialization-using-bytebuffer-and.html – assylias

+0

Puoi provare a completare il wrapping di FileInputStream con un BufferedInputStream? –

risposta

4

deserializzazione è piuttosto costoso. Se si utilizza la deserializzazione generica, verrà utilizzata molta riflessione e creazione di oggetti.

Ci sono molte alternative che sono più veloci e utilizzano la maggior parte del codice generato anziché la riflessione.

http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

Noterete che uno dei più veloci sta usando Externalizable che può essere un'opzione per voi. Ciò significa aggiungere metodi personalizzati per la serializzazione e la deserializzazione degli oggetti.

ho scritto molto approcci più veloce, ma questo evitare di creare gli oggetti da loro riciclaggio o utilizzando i dati nel file sul posto (vale a dire senza bisogno di deserializzare loro)

2

E 'difficile da dire senza guardare questo con un profiler o sapere molto sulla reale gerarchia della struttura del tuo oggetto, ma sto assumendo che se è "abbastanza complesso" e dell'ordine di "diversi GB", probabilmente stai gestendo migliaia di singoli oggetti.

La mia ipotesi migliore è che le prestazioni vengano eliminate da Java Reflection. Reflection è usato per costruire gli Oggetti dal tuo stream, che è noto per essere almeno due ordini di grandezza più lento di chiamare i costruttori direttamente all'interno del codice. Quindi se il tuo oggetto ha tonnellate di oggetti "piccoli", Reflection passerà molto tempo a ricostruirli.

Una cosa che si potrebbe provare (se non l'hai già fatto) sarebbe quello di dichiarare la seguente riga nella parte superiore di ciascuna delle vostre Serializable classi:

private static final long serialVersionUID = [some number]L; 

Se non si dichiara questo ID, Java dovrà calcolarlo, quindi salverai alcuni cicli della CPU dichiarandolo.

Per ulteriori riferimenti:

http://oreilly.com/catalog/javarmi/chapter/ch10.html

Problemi correlati