2012-04-10 8 views
5

Ich habe ein Java-Programm, das Daten in eine ziemlich komplexe und große Datenstruktur im Speicher (mehrere GB) bereitet und es auf die Festplatte serialisiert, und ein anderes Programm, das die serialisierte Datenstruktur im Speicher zurückliest. Ich war überrascht zu bemerken, dass der Deserialisierungsschritt ziemlich langsam ist und dass er CPU-gebunden ist. (100% CPU-Auslastung in top aber nur 3 bis 5 MB/s lesen mit iotop, die sehr niedrig ist für was sequenzielle Lesevorgänge auf einer Festplatte sein sollte). Die CPU ist relativ neu (Core i7-3820), die Struktur passt in den Speicher, kein Swap-Space ist konfiguriert.Warum ist die Deserialisierung von Java CPU-gebunden?

Warum ist das so? Gibt es eine alternative Möglichkeit, Objekte in Java zu serialisieren, die nicht die CPU als Engpass haben? Hier

ist die Deserialisierung Code, falls das wichtig ist:

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

IIRC es Reflexion Magie vergleichbar, wie die .NET-Serializer Arbeit verwendet. Das ist langsam. Es gibt einen konzeptionell einfachen, aber "viel Tipp" -Weg, um all dies zu vermeiden - tun Sie es von Hand. Das heißt, Objekte rekursiv Feld für Feld in einen binären Stream schreiben. Und umgekehrt zum Laden. – harold

+1

Dies könnte helfen: http://vanillajava.blogspot.co.uk/2011/10/serialization-using-bytebuffer-and.html – assylias

+0

Können Sie versuchen, den 'FileInputStream' mit einem' BufferedInputStream' zu umhüllen? –

Antwort

4

Deserialisierung ist ziemlich teuer. Wenn Sie die generische Deserialisierung verwenden, wird viel Reflexion und Erstellung von Objekten verwendet.

Es gibt viele Alternativen, die schneller sind und die meisten generierten Code anstelle der Reflexion verwenden.

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

Sie werden feststellen, dass eine der am schnellsten Externalizable verwendet, die eine Option für Sie sein kann. Dies bedeutet, dass benutzerdefinierte Methoden für die Serialisierung und Deserialisierung von Objekten hinzugefügt werden.

Ich habe viel schnellste Ansätze geschrieben, aber dies zu vermeiden alle Objekte zu schaffen, indem sie das Recycling oder die Verwendung der Daten in der Datei an Ort und Stelle (dh ohne sie zu deserialisieren)

2

Es ist schwer, dies zu sagen, ohne hinzusehen mit ein Profiler oder viel Wissen über die tatsächliche Hierarchie der Struktur Ihres Objekts, aber ich nehme an, dass, wenn es "ziemlich komplex" und in der Größenordnung von "mehreren GB" groß ist, Sie wahrscheinlich mit Tausenden von einzelnen Objekten zu tun haben.

Meine beste Schätzung hier ist, dass Ihre Leistung von Java Reflection getötet wird. Reflection wird verwendet, um die Objekte aus Ihrem Stream zu konstruieren, von denen bekannt ist, dass sie mindestens zwei Größenordnungen langsamer sind als Konstruktoren, die direkt im Code aufgerufen werden. Wenn Ihr Objekt also Tonnen von "kleinen" Objekten hat, wird Reflection viel Zeit damit verbringen, sie zu rekonstruieren.

Eine Sache, die Sie könnten versuchen (wenn Sie nicht bereits haben) wäre die folgende Zeile an der Spitze jeder Ihrer Serializable Klassen zu deklarieren:

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

Wenn Sie diese ID nicht erklären, Java muss es berechnen, also speichern Sie einige CPU-Zyklen, indem Sie es deklarieren.

Weitere Referenz:

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

Verwandte Themen