Java Externalizable vs. Serializable
Statt des Java Interfaces Serializable kann mit dem alternativen Interface Externalizable die volle Kontrolle über den Vorgang der Serialisierung übernommen werden. Insbesondere lässt sich in vielen Situationen der Speicherbedarf des serialisierten Objekts deutlich verringern, indem man bewusst auf einigen Overhead verzichtet. Um diesen Unterschied zu messen, kann man zwei Klassen erstellen, die jeweils Serializable bzw. Externalizable implementieren und einige Variablen mit festen Werten enthalten. Anschließend schreibt man diese Objekte via ObjectOutputStream und FileOutputStream in zwei Dateien und betrachtet die resultierende Dateigröße – allerdings nicht die Dateigröße auf der Festplatte, die von der Blockgröße des Dateisystems abhängt, sondern nur die Größe des eigentlichen Inhalts. Ich möchte hier auf ein paar Dinge hinweisen, die mir beim Experimentieren aufgefallen sind. Versuchskaninchen waren zwei Klassen E und S im Package C mit jeweils zwei Variablen des primitiven Typs int. E implementiert Externalizable, S Serializable.
- E belegt 35 Byte, S belegt 42 Byte.
- Ein paar oberflächliche Vergleiche im Hex-Editor deuten darauf hin, dass die ersten 10 Byte unabhängig von der Klasse sind (Windows 7 64-Bit), ob das jetzt allgemeiner Java-Overhead ist oder mit der Speicherung als Datei zu tun hat weiß ich nicht.
- Fügt man eine dritte int-Variable in beiden Klassen hinzu, belegt E wie erwartet 39 Byte, S belegt allerdings 51 Byte. S ist also um 5 Byte mehr gewachsen, als nötig wäre.
- Erhöht man auf 20 int-Variablen je Klasse, so belegt E 107 Byte und S bereits 214 Byte. Was int betrifft, benötigt Serializable auf Dauer mehr als doppelt soviel Speicher.
- Schreibt man bei Verwendung von Externalizable mit ObjectOutput.writeObject() statt mit ObjectOutput.writeInt(), so benötigt das Objekt 292 Byte. Der Speichervorteil geht komplett verloren, da man die Serialisierung im Grunde dem Integer-Objekt überlässt. Damit dieses später auch wieder als Integer-Objekt ausgelesen werden kann, werden die Informationen “java.lang.Integer” und “java.lang.Number” (Oberklasse von Integer) ebenfalls gespeichert. Buchstabe für Buchstabe ein weiteres Byte. Zudem dürfte auch mehr als der reine Inhalt des Integers gespeichert werden, immerhin verbrauchen wir hier fast 200 Byte mehr.
- Zurück zur bisherigen Klasse E und ihren 107 Byte. Wenn wir das Package “C” in “Compressor” und die Klasse “A” in “MyExternalizableClass” umbenennen, benötigt das resultierende Objekt 136 statt 107 Byte. Jeder zusätzliche Buchstabe in Package- und Klassenname, hat mit einem Byte zu Buche geschlagen.
- Lässt man E von einer anderen Klasse erben, erhöht sich der Speicherbedarf ebenfalls, auch wenn man eventuell vorhandene Variablen der Oberklasse nicht speichert.
to be continued…