# ObjectOutputStream#writeObject() zu langsam.



## tuxedo (29. Feb 2008)

Kennt jemand ne Methode um ein beliebiges Objekt anders zu serialisieren als mit "ObjectOutputStream#writeObject()"?

Nach zahlreichen Profiler-Versuchen hat sich rausgestellt dass das das Haupt-Bottleneck meines SIMON-Projekts ist...
Nur hab ich noch keine Idee wie ich's besser machen kann. 

- Alex


----------



## André Uhres (29. Feb 2008)

Datenbkank?


----------



## tfa (29. Feb 2008)

Du könntest mit java.io.Externalizable, java.ibjectOutput und java.ibjectInput alles selber implementieren. Keine Ahnung, ob man damit viel rausholen kann. Hab ich noch nie eingesetzt.


----------



## tuxedo (29. Feb 2008)

@André

Was soll ich mit ner Datenbank? Es geht um Socketkommunikation zwischen Client und Server. 

@tfa
Ja, das hab ich jetzt nahc einiger Zeit googeln auch rausgefunden. Ich frag mich nur wie RMI das schneller hinkriegt. Als ich letztes mal im Source von RMI geschaut hatte, hab ich, wenn ich ich recht entsinne, gesehen dass die nicht einfach auf alles und jeden writeObject loslassen. Die schauen was für eine Art Objekt das ist und serialisieren dann entsprechend auf "einfacherer" ebene. ein byte[] als Objekt zu serialisieren ist ja nicht so der Bringer. Gleiches gilt für die Primitiven Typen wie Integer, oder auch andere Sachen wie String. Da lässt sich vllt. mehr rauskitzeln wenn man das anders behandelt. Aber bei Objektgeflechten die ganze Abhängigkeitsbäume haben, wird das nicht gehen. Und ich glaube fast nicht dass sich Object*Stream so viel besser implementieren lässt was solche aufwendigen Objekte betrifft.

Das "seltsame" ist:

Ich transportiere keinen primitiven Datentyp oder nur nen String. Auch kein reines byte[].

Ich hab mir ein Transport-Objekt gebastelt das eine ID in Form eines Strings enthält und ein byte[] das die Daten darstellt.

Auch RMI müsste dieses Objekt als "nicht-String" und "nicht-Integer" erkennen und als "komplexes Objekt" behandeln und somit "normal" mit readObject und writeObject serialisieren.
Würde ich nur ein byte[] transferieren, so würde mir's mittlerweile einleuchten. Aber so.... hmmpf.

Da Simon und RMI dann eigentlich die gleichen Techniken verwenden ist es "sonderbar" dass RMI Anhand meiner vorliegenden Zahlen dennoch schneller ist.

Und als eindeutiges Bottleneck hab ich eindeutig die write und readObject Methode identifiziert. 

Jetzt stehe ich vor einem Rätsel...

- Alex


----------



## André Uhres (29. Feb 2008)

alex0801 hat gesagt.:
			
		

> @André
> Was soll ich mit ner Datenbank?


Meine Frage sollte dich nur aus der Reserve locken, damit jeder erkennt, worum es geht :wink:


----------



## tuxedo (29. Feb 2008)

Will keine Grundsatzdiskussionanfangen. Aber auch ohne zu wissen was "SIMON" ist war die Frage klar: Gibt einen schnelleren weg als writeObject() ...

Zu tfa's Vorschlag mit Externalizable ...
Es soll für beliebige Objekte gehen. Externalizable setzt vorraus dass die Objekte für's serialisieren "speziell" aufbereitet sind. 

Bin gerade dabei zu schauen wie ich Objekte selbst analysieren kann. Klar, geht mit Reflection. Aber da bin ich gerade auf ein Problem gestoßen:

Was mach ich mit Instanzvariablen welche "private" sind? Da komm ich scheinbar nicht ohne weiteres dran. Dennoch sind diese Felder wichtig für die verwendung des deserialisierten Objekts. 

In diversen RMI-Dokus hab ich gelesen dass dort auch private Felder ausgelesen und gesetzt werden können.
Ist jemand in Relfection so fit und kann mich da auch den richtigen Trichter bzgl. der privaten Felder bringen?

-Alex

[update]

Ein


```
field.setAccessible(true);
```
 brachte das gewünschte Ergebnis ;-)


----------



## SlaterB (29. Feb 2008)

meine Güte, Simon schreiben aber nicht mal Reflection-API lesen? 


```
public class Test
{

    private String test = "auto";

    public static void main(String[] args)
        throws Exception
    {
        Test t = new Test();
        Field f = t.getClass().getDeclaredField("test");
        System.out.println(f.get(t));
    }

}
```

> Da komm ich scheinbar nicht ohne weiteres dran.

wie kommst du denn sonst ran, suchst du nach getter/ setter?

edit: ok, bei anderen Klassen als der eigenen ist es schwieriger  ich lese ja auch nicht


----------



## André Uhres (29. Feb 2008)

alex0801 hat gesagt.:
			
		

> .auch ohne zu wissen was "SIMON" ist war die Frage klar: Gibt einen schnelleren weg als writeObject() ..


Ja, im Netzwerkforum wär's klar wie Jauche. Hier nicht so besonders.


----------



## tuxedo (29. Feb 2008)

@SlaterB
Es ging um "private" Fields... An public war's kein Thema. Bei private jetzt aber auch nicht mehr.

@André
Naja, sind wir hier nicht im Perfomance-Board? Ach, ich vergaß.. Wird ja abgeschafft. Beim nächsten "Gibt einen schnelleren weg als writeObject() ..." Problem frag ich dann dort nach. Versprochen ;-)


----------



## Illuvatar (29. Feb 2008)

Hmm... bist du eigentlich sicher, dass das _Serialisieren_ das langsame ist? Oder könnte evtl. die Netzwerkverbindung noch besser ausgenutzt werden? Aus dem Profiling-Test den du gepostet hast schien es für mich, dass das nicht klar hervorgeht. Vielleicht solltest du mal was mit Channels probieren, die sind stark Performance-opimiert.


----------



## Janus (29. Feb 2008)

ich stimm illuvator da mal zu. reflection ist zwar "langsam", aber in relation zu socket streams ist das ne rakete. wenn die profiling ergebnisse wirklich stimmen, kann ich mir nur vorstellen, dass du beim serialisieren irgendwas ungeschicktes anstellst.

um mal ein beispiel aufzuzeigen: ich hatte mal einen sehr kruden parser für formatierten text gestrickt und eclipse profiling tools haben mir angezeigt, dass der code ca. 60% der zeit in diesem parser verbringt. also hab ich den optimiert, bis der neue parser um faktor 100 schneller war als der alte. trotzdem hat sich die performance der lib nur um sehr wenige prozent erhöht.

der grund war zweigestaltig: der profiler hatte die hohe cpu last während des parsens als kritisch eingestuft. tatsächlich ging 60% der last für das parsen drauf und ein verschwindend geringer lastanteil (< 1%) für die anschließende datenbankverbindung. allerdings machte der laufzeitanteil der DB verbindung über 90% aus.
die optimierung des parsers hat also höchstens mein gewissen beruhigt, aber kaum nen vorteil gebracht


----------



## angelchr (1. Mrz 2008)

hi,
also ich hatte vor kurzem ein ähnliches Problem mit der Geschwindigkeit. Bei mir ging es um ein  Spiel. Ich hatte die Geschwindigkeitsprobleme NUR zwischen 2 Windows Clients. 2 Linux Clients haben das problemlos bewältigt. Ich hab mich dann für eine Lösung ohne Serialisierung entschieden. Das gleiche Problem!!! 
Socket.setTcpNoDelay(true); brachte mir die erforderliche Geschwindigtkeit. Ich hab es nicht mehr mit serialisierung probiert, allerdings gehe ich davon aus, dass es funktioniert hätte.


Gruß

Angelchr


----------



## tuxedo (1. Mrz 2008)

Also den Nagle-Algo hab ich schon abgeschaltet (setTcpNoDelay(true)).

Ich benutze immer RMI als vergleich. RMI nutzt auch "reine" Socketverbindungen und kein Java.NIO. Von daher muss ich das doch genauso schnell hinbekommen.

Die Socketeinstellungen (Nagle und Puffer und Co.) sind bei Simon schon seit längerem 1:1 gleich mit RMI. 

RMI benutzt auch das serialisieren. Und dennoch ist es schneller.
Dass es am Netzwerkdevice liegt schließe ich mal aus. 
Zum einen teste ich mit localhost, und zum anderen lasse ich 1:1 den gleichen Test auf 1:1 der gleichen Maschine mit RMI laufen.

Ich werd jetzt versuchen irgendwie anders zu serialisieren, bzw. das Profiling weiter auszuweiten. Hab ja den Source von allem (hab das JDK-Source Paket runtergeladen). 

- Alex


----------



## tuxedo (4. Mrz 2008)

Der Konsistenz halber:

Problem gelöst/gefunden. Siehe http://www.java-forum.org/de/topic65225_verflixtes-speicherleck.html


----------

