EnumSet-Serialisierung

8

Ich habe gerade ein paar Stunden mit dem Debuggen meiner App verloren, und ich glaube, ich bin auf einen (anderen o_O) Java Bug gestoßen ... schnüffle ... ich hoffe es ist nicht, denn das wäre traurig : (

Ich mache folgendes:

  1. Erstellen eines EnumSet mask mit einigen Flags
  2. Serialisierung (mit ObjectOutputStream.writeObject(mask) )
  3. Löschen und Setzen einiger anderer Flaggen in mask
  4. Serialisierung erneut

Erwartetes Ergebnis: Das zweite serialisierte Objekt unterscheidet sich von dem ersten (spiegelt die Änderungen in der Instanz wider)

Ergebnis erhalten: das zweite serialisierte Objekt ist die genaue Kopie des ersten serialisierten Objekts

Der Code:

%Vor%

Es druckt:

%Vor%

Verwende ich EnumSet falsch? Muss ich jedes Mal eine neue Instanz erstellen, anstatt sie zu löschen?

Danke für Ihre Eingabe!

**** UPDATE ****

Meine ursprüngliche Idee war es, ein EnumSet als Maske zu verwenden, um anzugeben, welche Felder in der folgenden Nachricht vorhanden oder abwesend sein werden, also eine Art Optimierung der Bandbreite und der CPU-Nutzung. Es war sehr falsch !!! Ein EnumSet braucht Zeitalter, um zu serialisieren, und jede Instanz benötigt 30 (!!!) Bytes! So viel zur Weltraumwirtschaft :)

Kurz gesagt, während ObjectOutputStream für primitive Typen sehr schnell ist (wie ich bereits in einem kleinen Test herausgefunden habe: Ссылка

Also habe ich daran gearbeitet, indem ich mein eigenes EnumSet erstellt habe, das von einem int unterstützt wird, und das int direkt serialisieren / deserialisieren (nicht das Objekt).

%Vor%

Es ist etwa 130 mal schneller während der Serialisierung und 25 mal schneller während der Deserialisierung ...

MyEnumSets:

%Vor%

Reguläre EnumSets:

%Vor%

Es ist jedoch nicht so sicher. Zum Beispiel funktioniert es nicht für Enums mit mehr als 32 Einträgen.

Wie kann ich sicherstellen, dass die Enumeration weniger als 32 Werte für MyEnumSet-Erstellung hat?

    
Denis 16.12.2015, 16:22
quelle

1 Antwort

12

ObjectOutputStream serialisiert Verweise auf Objekte und beim ersten Senden eines Objekts das tatsächliche Objekt. Wenn Sie ein Objekt ändern und erneut senden, sendet alle ObjectOutputStream die Referenz erneut an dieses Objekt.

Das hat ein paar Konsequenzen

  • Wenn Sie ein Objekt ändern, sehen Sie diese Änderungen nicht
  • es muss einen Verweis auf jedes Objekt erhalten, das jemals gesendet wurde, an beiden Enden. Dies kann ein subtiler Speicherverlust sein.
  • Der Grund dafür ist, dass Sie Graphen von Objekten statt von Bäumen serialisieren können. z.B. A zeigt auf B, der auf A zeigt. Sie möchten nur einmal senden.

Um dies zu beheben und etwas Speicher zurück zu bekommen, rufen Sie Zurücksetzen () nach jedem vollständigen Objekt. z.B. vor dem Aufruf von flush()

  

Reset ignoriert den Status von Objekten, die bereits in den Stream geschrieben wurden. Der Status wird so zurückgesetzt, dass er einem neuen ObjectOutputStream entspricht. Der aktuelle Punkt im Stream wird als zurückgesetzt markiert, sodass der entsprechende ObjectInputStream am selben Punkt zurückgesetzt wird. Objekte, die zuvor in den Stream geschrieben wurden, werden nicht als bereits im Stream befindlich bezeichnet. Sie werden wieder in den Stream geschrieben.

Ein anderer Ansatz besteht darin, writeUnshared zu verwenden , jedoch gilt dies für das Toplevel-Objekt mit einer flachen Unsharedness. Im Falle von EnumSet wird es anders sein, aber die Enum[] Wraps sind immer noch geteilt o_O

  

Schreibt ein "nicht gemeinsam verwendetes" Objekt in den ObjectOutputStream. Diese Methode ist identisch mit writeObject, außer dass das angegebene Objekt immer als neues, eindeutiges Objekt im Stream geschrieben wird (im Gegensatz zu einer Rückreferenz, die auf eine zuvor serialisierte Instanz verweist).

Kurz gesagt, nein, das ist kein Fehler, sondern erwartetes Verhalten.

    
Peter Lawrey 16.12.2015, 16:27
quelle

Tags und Links