Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (487)
Games in Android Showcase (110)
games submitted by our members
Games in WIP (552)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Serialization without creating new Objects for the GC  (Read 4798 times)
0 Members and 1 Guest are viewing this topic.
Offline CommanderKeith
« Posted 2005-11-24 06:45:31 »

[Edit: latest source and discussion here: http://www.java-gaming.org/topics/multiplayer-top-down-view-shooter/18019/view.html, in 'Game Showcase under title 'Multiplayer top-down view shooter']

Dear Developers,

I've made a pair of custom Serialization streams to combat 2 important Serialization problems in a networked game I'm trying to build. 

Problem 1: new Objects are created when deserializing the game world 40 times per second. This causes the Garbage Collector (gc) to periodically hog processor time (15% GC tick count) to cleanup the redundant objects. When this happens in the middle of a screen paint (rendering takes 75% of processor time), the game appears to lag badly, making the whole application appear to 'chug' as the gc kicks in about every second.

Problem 2: on the client VM, since the GameWorld object is recreated all the time, the client has no reference to its own up-to-date Player object, it has to search for its name field in the list of Players. Similarly there are other things that I want to keep a reference to on the client without having to give names to everything and looping through lists to find the right Object.

These problems led me to think - why not have a Serialization class that just updated objects by replacing their primitives but not the whole object? In other words, why does deserialization have to create new objects when they already exist?

So that's what I made, and I called it SuperSerialization (SS).   The code for the new SS streams is posted at:

http://www.slavebot.net/SuperSerializable/SuperSerializableIntro

The 'SuperSerializable' (SS) streams are made for network computer games where the developer wants to update the client's game world so that it is the same as that on the server.  The SS streams allow you to update objects rather than replace them.  Now we can send our whole game world over the network without having to recreate the object in deserialization.

How Does It Work?

The four key classes are SSObject, SSAdapter, SSObjectOutputStream and SSObjectInputStream.  They are not very big classes (< 350 lines each) so I recommend that you look at the code, but I'll try to explain how it works.

The SSObjectOutputStream extends DataOutputStream.  It defines two key methods writeSS(SSObject sso) and writeDone() and clearStoredExceptFor(SSObect sso).  SSObjectInputStream works similarly, with readSS(SSObject sso) and readDone(). 

The SSObjectOutputStream can not update normal Objects.  It can write some types of Objects (see attemptWriteNonSS()), but it can only update objects that implement the interface SSObject (the object must also have a no-argument constructor).  The SSObject interface defines methods getCode(), writeSS(SSObjectOutputStream out), readSS(SSObjectInputStream in) and collectMemberSSCodes(ArrayList objectCodes).  The getCode() method returns the unique integer code that is used to identify it.  Without this unique identifying number, on the client side we couldn't find the unique object that needs updating.  This is why the SS streams can't write normal objects - their hash codes are not unique so two different objects can't be discriminated.  writeSS and readSS are just like normal Serialization's writeObject and readObject - they are called to write/read the object's data to/from the stream. 

Since all SSObjects read in SSObjectInputStream are stored in the HashMap storedObjects, when these objects are no longer used they need to be recycled and put back in spareObjects, so collectMemberSSCodes(ArrayList objectCodes) is used to find out what SSObjects need to be kept in storedObjects.  Any objects implementing SSObject need to be able to find all SSObject references that the object contains and add their code to the list to avoid having these SSObject members recycled.

There is an adapter class SSAdapter that implements SSObject and calls the SS streams' default write and read methods as well as the default collectMemberSSCodes method.  These methods use the Reflection API to find the SSObject's specific fields and then writes/reads them to/from the stream.  Any that you don't want written you can mark with the transient modifier, just like normal Serialization.  Similarly, static fields are not written.

How Can I Use It?

To use the SS streams you just get your game objects to extend SSAdapter and have a no-arg constructor.  On the server, your game loop would look like this:

ByteArrayOutputStream byteOut = null;
SSObjectOutputStream objectOut = null;
byte[] bytes = new byte[0];

try{
   byteOut = new ByteArrayOutputStream();
   objectOut = new SSObjectOutputStream(byteOut);
} catch(IOException e){}

GameWorld gameWorld = new GameWorld();   // GameWorld extends SSAdapter

while(true){
   try{
      gameWorld.update();   // do the game logic
      
      byteOut = new ByteArrayOutputStream();
      objectOut.setOutputStream(byteOut);
      objectOut.writeSS(toBeWrittenObj);
      objectOut.writeDone();
      bytes = byteOut.toByteArray();
      // then send the bytes over the network
   }catch(java.io.IOException e){}
}



On the client, it would look like this:

ByteArrayInputStream byteIn = null;
SSObjectInputStream objectIn = null;
byte[] bytes = new byte[0];

try{
   byteIn = new ByteArrayInputStream(bytes);
   objectIn = new SSObjectInputStream(byteIn);
} catch(IOException e){}

GameWorld gameWorld = null;
while (true){
   try{
      bytes = ...;   // Get the bytes sent from the server
      byteIn = new ByteArrayInputStream(bytes);
      objectIn.setInputStream(byteIn);
      gameWorld = (GameWorld)objectIn.readSS();
      // after the first objectIn.readSS(), gameWorld is created.
      // Thereafter, it is only updated but a reference is still returned.
      objectIn.readDone();
      objectIn.clearStoredExceptFor(gameWorld );
      // gets rid of and recycle old SSObjects that are no longer referred
      // to in the GameWorld so that they don't cause a memory leak.
      // This can be done every so often, not needed after every readSS call

      // now paint the gameWorld etc.
   }catch(java.io.IOException e){}
}

Complications

This works fine when all of our game objects extend SSAdapter, but all of their fields and those field's fields, etc must extend SSAdapter.  For objects that can't extend SSAdapter you need to sub-class them and implement SSObject.  My game world contains ArrayLists so I sub-classed it in ArrayListSS (see the posted code).

This works fine, now my ArrayListSS's can be updated.  But some classes are final like String.  For these, we have to use SSObjectOutputStream.attemptWriteNonSS() and have a custom way of writing the string.  These Strings won't be able to be updated, they will be newly created with each readSS(), just like normal Serialization, but worse.  Worse because of this: say you store a player's name in a list in the GameWorld, and also in the Player object.  On the server, these two references are to the same object, so name == player.name.  But when the client updates the GameWorld with readSS,  name .equals(player.name) but name != player.name since the references are not to the same object. 

This problem is not serious however since with careful design it can be overcome.  For example, if the GameWorld stored the list of Players rather than just name Strings, the two names will be == since their Player objects would be ==.

In my version of SSObjectOutputStream.attemptWriteNonSS(), arrays, Strings, and Colors can be written but have the above problem.  Having too many of these objects in your game world will cause big GC pauses since they are newly made with each readSS method call.

Note that over-riding SSAdapter.writeSS() and readSS() makes for faster Super Serialization since no reflection is needed.  If you do over-write these methods, note that it is only called once on that object, so you must write all fields defined in this object's class-level as well as all super-class levels (unlike in Serialization's writeObject and readObject).  Also, for any SSObject fields that are members of the object being written, you should call SSObjectOutputStream.writeSS(theObject) on them.

Garbage Collection

For my game world, -Xprof showed that garbage collection went from 15% (regular Serialization) to 5% (SS) and that is with a GameWorld that had 293 SSObjects and 43 normal non-SSObjects written/read.  If there were fewer of these Objects or with a better way of transfering them, garbage collection could near 0%.  Unfortunately the 5% GC tick count is still far too high and makes the application appear laggy as the GC chugs into action about once a second.

This leads to my second problem: can we do something more efficiently with the non-SSObjects to update them without re-creation on every call to readSS()? 

Thanks, any help would be appreciated.
Keith

(I've also put up this post on the Java Serialization Forum http://forum.java.sun.com/thread.jspa?threadID=675403&tstart=0)


Offline CommanderKeith
« Reply #1 - Posted 2005-11-24 07:34:01 »

Sorry, I stuffed up the page where the code is posted, its

http://www.slavebot.net/SuperSerializable/SuperSerializableIntro.htm

Offline tom
« Reply #2 - Posted 2005-11-25 02:31:02 »

What struck me is that in order to stress the garbage collector that much you must be sending a huge amount of data. Have you mesured or calculated the number of bytes per second you are transmitting? Are you planing on running it on the internet or is it only a LAN game.

Most people will try to make their game run on the internet. Then the limiting factor is clearly the bandwidth. It's unlikely you can transmit enough data to impact garbage collector.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Ask_Hjorth_Larsen

Junior Member




Java games rock!


« Reply #3 - Posted 2005-11-25 16:01:51 »

It seems that the htm file tries to access files on 127.0.0.1, i.e. the one who is browsing it.

May I recommend that you use ex.printStackTrace(); whenever you catch an exception? Otherwise the program may fail silently e.g. if there's a problem with an output stream, and it will be difficult to debug without being sure when and where the exception was thrown.
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #4 - Posted 2005-11-25 16:04:45 »

I agree with Tom - unless you are running this on a very old computer, it should be next to impossible to lag a game from GC using networked data, unless you are sending WAY to much.  How many times a second are you updating your world?  20 updates/sec is a typical number used for FPS's.  

Also, instead of sending the whole world, you might want to only send values that have changed.  Even in a fast paced multiplayer action game you probably only have a 50% data change between one frame and the last.

Offline tom
« Reply #5 - Posted 2005-11-25 17:17:56 »

He says he is deserializing the game world 40 times per second. In the other thread he said he was testing on a gameworld with 336 objects. That is 13440 objects a second. He don't mention the size of the objects. But if we assume an average size of 20 bytes (5 floats) it means he must be sending 268800 bytes per game state. If the server has 16 clients connects it means it must send 4300800 bytes per second or in other words 34 MBits/s. Wich is starting to push the limits of a what a LAN can handle.

Offline Jeff

JGO Coder




Got any cats?


« Reply #6 - Posted 2005-11-25 21:01:53 »

Serialization itself has costs.

In general I recommend against tryign to use it for this kind of information flow.

Its generally cleaner, easier, faster and more controllable to just invent a binary packet protocol for the data.

What he ash done above strikes me personally as reforging a hammer to try to turn it into a screwdriver.

YMMV.

JK

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline Ask_Hjorth_Larsen

Junior Member




Java games rock!


« Reply #7 - Posted 2005-11-26 04:06:16 »

1  
20 updates/sec is a typical number used for FPS's.


That's a very slow framerate for first person shooters. Generally this works on television because of blur and stuff, but on a computer you need (at least) around 40 to ensure reasonably smooth movement.
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #8 - Posted 2005-11-26 05:58:46 »

20 server frames per second sent to clients over the network (game state), not rendering frames per second. 

Offline rolz

Junior Member




Chief Technopolitan


« Reply #9 - Posted 2005-11-26 12:44:23 »

I bet the "Super" serialization is a solution looking for a problem. If the game sends megabytes of data each second then how about redesigning the game to send less data ? I can't recommend much but even with transmitting only changed values and avoiding serialization you can get much better results. In Technoploies the bandwidth is 50-200 bytes/second on a map with 5-25 active players, 5-25 static objects - and yet playable with its 128kbit/sec laggy server

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Ask_Hjorth_Larsen

Junior Member




Java games rock!


« Reply #10 - Posted 2005-11-26 15:25:02 »

Quote
20 server frames per second sent to clients over the network (game state), not rendering frames per second.

Seems reasonable then. This, however, would demand some kind of interpolation on the client, which there probably isn't in this case seeing as the current rate is 40 fps.
Offline Vorax

Senior Member


Projects: 1


System shutting down in 5..4..3...


« Reply #11 - Posted 2005-11-26 16:10:00 »

To Rolz and AskHjorth_Larsen - Agreed on both counts.  The wrong problem is being tackled.

Offline CommanderKeith
« Reply #12 - Posted 2005-11-26 18:57:02 »

Hi Everyone,
Thanks for the discussion. 

I should have explained myself better so I'll clear it up.  First, I'm sending a lot of data - 10,000 bytes a frame with SS and 12,000 with regular Serialization, 40+ FPS.  However this is the whole kit and caboose, the unchanged game world objects included.  I'll come back to this.

The real-time LAN game I am trying to build is one where the clients send only user events to the Server and the Server sends the game world back to them, and on reciept the clients paint it.  I'm using dumb clients - they don't update their own game world and so there's no interpolation. 

You can see why I had so much trouble with regular Serialization then- the continual reconstruction of the game world meant that the client couldn't hold on to any references of its Player object, the scores, its view position, etc.  The other problem was the garbage collector because it would gum up the client so that it displayed frames late, and since the client couldn't compensate for this by updating the game world according to the longer period of time, it made the client's game appear to lag. 

This dumb-client architecture is attractive because its so simple to implement, except for the above problems.  This is why I made the SS streams - they should allow such an architecture to function well over a LAN where communication speeds are negligible so the client can afford to be dumb.

With the SS streams, the disappearing reference problem is solved.  But little did I realise the folley in trying to fight the GC-lag by trying to reduce the % GC ticks.  Even after optimising the SS streams so they created less objects (I got the GC tick count down to 4% with SS from 15% with regular Serialisation) it just meant that instead of lagging the client out once every second, the client lagged out once every 5 seconds  >>  bugger.

However, after reading Tom's posts about the amount of data I'm sending I tried making the game world a lot smaller (from 10,000 bytes to 5,000 bytes / frame).  Now the GC-lag on the client still occurs but is even less frequent.  With the -Xincgc option the client runs nearly as smooth as the server using the SS streams (but of course Serialization lags badly).  Now I realise that since I send only half the data compared with before, less garbage is created even though the % GC tick count is the same.  This is why the garbage collections are fewer and further between.

Of course I don't want to play in the small world, so I'm working on a way to send only the changing objects rather than the stationary ones (like obstacles), and this is where the SS streams may be really handy.  Since you can over-ride an SSObject's writeSS & readSS methods you can customise what is written & read so you can leave what hasn't changed alone.  This is impossible in normal Serialization since it insists on re-constructing everything.

Due to the use of the UDP protocol between server and clients, I'll have to implement a custom checking procedure so that the client can tell the server that it has recieved the unchanging objects.  Then the server can write only the changing objects in the game world using the game world's over-riden writeSS method.

So the SS streams aren't a solution looking for a purpose, though I appreciate the commentary.  Apart their application to this dumb-client architecture, I think they would have great use in any architecture that uses TCP communication since the SSObjects could have their writeSS methods over-ridden to write only the fields that had changed.

In my (biased) view the SS streams are in many ways a ready-made binary packet protocol for the data of the game world.  Without having to fiddle with it, it will work as is (but it will send too much data), but with tuning it can send much less.  After all, the SS streams are just DataIn/OutputStreams.  One of the best things about the SS streams compared with custom binary data packets is that they take care of tricky situations like this:

A new client connected to the Server and so a new Player object was created on the server.  It was given a bunch of other existing game objects as members (team mates, vehicles the player was given control of, etc).  Using a packet of data , how can you create the Player object on the client and make it so that the references in this new object are == to the same objects that the client already has in its game world?

The SS streams can do this efficiently if the Player class's write & readSS methods are over-ridden so that it writes the unique codes of its member SSObjects that already exist on the client.  When the client reads the Player, the Player's custom readSS method and plucks those existing SSObjects from its storedObjects HashMap using their unique codes, and then it just sets the new Player's fields equal to them.  Not too hard - you just need to have a smart pair of write & readSS methods. 

Please let me know what you think, good or bad.

Thanks,
Keith

PS: I've made the code more efficient and re-posted it on http://www.slavebot.net/SuperSerializable/SuperSerializableIntro.htm.  The SS streams are now as fast as regular Serialization (30% plus or minus, depends on what's sent), they write less data, and as expected they create much less garbage (run SSTester with your game world as a member to see for yourself).  Thanks to Martijn for his suggestion to cache the object fields to reduce Reflection.

Offline swpalmer

JGO Coder




Where's the Kaboom?


« Reply #13 - Posted 2005-11-26 23:22:38 »

1  
20 updates/sec is a typical number used for FPS's.


That's a very slow framerate for first person shooters. Generally this works on television because of blur and stuff, but on a computer you need (at least) around 40 to ensure reasonably smooth movement.

Minor point:  In terms of motion, televisions have at least 50 updates per second.  PAL, the format used most outside of North America  is 25 interlaced frames per second.  NTSC, the North American and Japanese format, is approximately 30 interlaced frames per second.  So temporally updates happen at twice those rates (50 ~60 updates per second).

The really "slow" thing is film.  Movie are 24 fps, and when the camera is panning you can really see it.  It works better than you might expect in a theater though, due to the dark environment and the "persistence" of the human vision system.

Offline Jeff

JGO Coder




Got any cats?


« Reply #14 - Posted 2005-11-27 00:28:49 »

since you ask for comments, a number of poitns:

(1) Do NOT call what you are doing serialization.  It isnt.  It breaks most of the gaurantees of Serialization as well as the fundemntal purpose-- which is to allow the state of an object to be preserved across VM instances.

(2)Your solution is inferior to a custom binary protocol because you have no control over what fields are sent.   You have to update the entire object even if one field changes. You are also sending all kinds of over-head to identify the object's class and the fields being updated that are part of the super-structure of Serialization. On your LAN game this may make little diference but for a net game bandwidth usage becomes important..

It also consumes sigificantly more CPU as that data needs to be unpacked and copied to the aprporpiate fields via the generic mechanisms of Serialization where a custom binary protocol would just read the values off the stream in order and deliver them via callback parameters.

(3) Your GC problems suggest fundemental architecture issues.  at a guess they have been driven by this Serialization-oriented focus.  Under a modern desktop VM you should be seeing no problem with short-lived obejcts, which is all a packet-type mechanism typically generates.  Instead, my guess is that you are delivering objects that you keep alive until the next data arrives, which is probably just long enough for them to be promoted out of the eden space.

A *common* source of performance problems in Java (though not as common now as it ocne was) is falling in love with Serialization. (Reflectionis a close second.)  It really is a very special purpose mechanism intended for pretty specific uses, and transmitting small packets of bytes that rapidly change *isn't* one of them.

Kudos on figuring out the under-side  of Serilaization, but I agree with the comments that you've solved the wrong problem the wrong way.

BTW: If this is a LAN only game there really is only one reason to *ever* use UDP and thats for multi-cast.  Other then that TCP is much more convenient and on a  LAN has no drawbacks.   If what you need is in fact reliable multicast, take a look at JRMS/LRMP.  Its a well solved problem.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline CommanderKeith
« Reply #15 - Posted 2005-11-27 09:56:21 »

Hi Jeff,
Thanks for your comments, in answer:

1) The naming is insignificant.  Its called Serialization because it serializes Objects into bytes.  Its similar to regular Serialization because if the object doesn't exist on the client, it is created.  If it already exists, its updated - thats the Super part.

2) "Your solution is inferior to a custom binary protocol because you have no control over what fields are sent. You have to update the entire object even if one field changes"

 - In fact you have near absolute control over what is written, you just over-ride the read & writeSS methods of the SSObject.  If only one field has changed, write that field only. 

"You are also sending all kinds of over-head to identify the object's class and the fields being updated"

 - I send just an int for each Object to identify its class but nothing is sent to identify the fields.  The only overhead that's sent which isn't directly controllable is the int that is a unique code which identifies the SSObject and the int that is written to signal its class (this is written in case the object doesn't exist and needs creation) .  Other than that, there is absolutely no overhead if you over-ride the writeSS and readSS methods of the SSObjects. 

I could have put the writing of these two ints in the default SSAdapter's write and readSS methods so this could be over-ridden as well but then the programmer would have to deal with this, so I traded efficiency for simplicity.  I invite you to put these parts of the SSInput and output stream's simple write & readSS methods (different from the SSObject's methods of the same name) into the default SSAdapter's code, but then when you are over-riding these default methods you'll have to identify the incoming object somehow so you don't try to read it more than once, and also you'll have to be able to gaurantee that it exists already.  Unless bandwidth really is an issue, I don't think that its worth the trouble to have to provide all of these checks if you do choose to change the code.

The SS streams extend DataIn/OutputStreams so by over-riding the SSAdapter's two default methods you are essentially creating a custom binary protocol.  Even if you don't over-ride them, there is no more overhead than the int signalling the class and the int signalling the unique code of the object (as above), and the contents of the fields (the names of the fields are never sent since they are put in alphabetical order and cached on both sides of the stream when the new class is first encountered). 

"It also consumes sigificantly more CPU as that data needs to be unpacked and copied to the aprporpiate fields via the generic mechanisms of Serialization where a custom binary protocol would just read the values off the stream in order and deliver them via callback parameters."

- CPU is not an issue.  Even with my big game world (10,000 bytes), the SS streams complete a write and read cycle in in 4 milliseconds flat.  If you are concerned about this, again, by over-riding the SSObject's writeSS and readSS methods you can set the fields yourself >> absolutely no overhead.  By using the default mechanism, there is Reflection involved, but as I said, the CPU cost is insignificant.

(3) "Your GC problems suggest fundemental architecture issues" - yes, the dumb-client framework.

"at a guess they have been driven by this Serialization-oriented focus" - absolutely, but with the SS streams the GC problem is nearly negligible.

"Under a modern desktop VM you should be seeing no problem with short-lived obejcts, which is all a packet-type mechanism typically generates. Instead, my guess is that you are delivering objects that you keep alive until the next data arrives, which is probably just long enough for them to be promoted out of the eden space."

- This is true, but what would you suggest?  Explicit nulling? 

The beauty of SS streams is that for SSObjects there is no garbage collection at all.  All redundant SSObjects are recycled by being dumped in SSObjectInputStream's spareObjects Map when the stream's clearStoredExceptFor(SSobject sso) method is called.  The next time a new SSObject is sent from the server, instead of instantiating a new one, an old one stored in spareObjects is plucked out.


Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #16 - Posted 2005-11-27 12:36:30 »

since you ask for comments, a number of poitns:

(1) Do NOT call what you are doing serialization.  It isnt.  It breaks most of the gaurantees of Serialization

It's serialization with a small "s" - IIRC sun didn't invent the term, and they don't get to own it Smiley.

A generally accepted definition (foldoc) is: "To represent an arbitrarily complex data structure in a location-independent way so that it can be communicated or stored elsewhere."

Quote
(2)Your solution is inferior to a custom binary protocol because you have no control over what fields are sent.   You have to update the entire object even if one field changes. You are also sending all kinds of over-head to identify the object's class and the fields being updated that are part of the super-structure of Serialization. On your LAN game this may make little diference but for a net game bandwidth usage becomes important..

Yep, but ... this is the same way that many pro games studios are going (have gone) Sad. I agree it's a foolish way in the wider sense, but it has considerable advantages in terms of simplicity to code against and to get up and running with a game with. In the long term, I believe we'll soon be seeing GD post-mortems "oh my god, don't use distributed-object-architectures to run a game - it's a nightmare!" but for the time being many people are happy with this approach.

Quote
It really is a very special purpose mechanism intended for pretty specific uses, and transmitting small packets of bytes that rapidly change *isn't* one of them.

Not so much "for a special purpose" as "not intended to be a high-performance system". I'd say it's a poor implementation done in minimal time and effort just enough to provide a basic service (nothing wrong with that - efficient use of development resources).It's not like the optimised Math.* methods, it's more like autoboxing - it provides the functionality at bare-bones performance. If you want better, pay for it or do it yourself.

malloc will be first against the wall when the revolution comes...
Offline Jeff

JGO Coder




Got any cats?


« Reply #17 - Posted 2005-11-28 02:02:30 »

Hi Jeff,
Thanks for your comments, in answer:

1) The naming is insignificant.  Its called Serialization because it serializes Objects into bytes.  Its similar to regular Serialization because if the object doesn't exist on the client, it is created.  If it already exists, its updated - thats the Super part.

Okay, maybe I am misunderstanding you.

Are you telling me you have done nothing to the encoding and *only*modified the decoiding logic?

What happens if the existing object is not of the right version? How are you dealign with mismatched SerialVersionUIDs ??

Quote
- In fact you have near absolute control over what is written, you just over-ride the read & writeSS methods of the SSObject.  If only one field has changed, write that field only. 

But you STILL have to send all those fields.  You have no chocie which fields are sent and cannot jsu tsend a partial set thata re udpated.

So in effect you have forced the programmer to push back their packet protocol into their object design.  Which I see as pretty bad effect.

"You are also sending all kinds of over-head to identify the object's class and the fields being updated"

Quote
- I send just an int for each Object to identify its class but nothing is sent to identify the fields. 

But ist wrappedin a standard Serized object, at leasta s I udnerstand 1 above, which means all the meta data from Serialization.

Have you actually *measured* the size of your objects serialized forms?


Quote
The beauty of SS streams is that for SSObjects there is no garbage collection at all.  All redundant SSObjects are recycled by being dumped in SSObjectInputStream's spareObjects Map when the stream's clearStoredExceptFor(SSobject sso) method is called.  The next time a new SSObject is sent from the server, instead of instantiating a new one, an old one stored in spareObjects is plucked out

In modern VMs pooling generally is a net-loss v. the eden space  with regards to short-lived obejcts,.

So I think you are likely creating yourself problems here ratehr then solving them.

As I said before, if you find aneed to pool arboitrary objects then you are holding onto short lived obejcst too long.  Which means you need to revist your app architecture.




Quote

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline Jeff

JGO Coder




Got any cats?


« Reply #18 - Posted 2005-11-28 02:05:17 »


Not so much "for a special purpose" as "not intended to be a high-performance system". I'd say it's a poor implementation done in minimal time and effort just enough to provide a basic service (nothing wrong with that - efficient use of development resources).It's not like the optimised Math.* methods, it's more like autoboxing - it provides the functionality at bare-bones performance. If you want better, pay for it or do it yourself.

You knwo i had to respond to this.

Its a perfectly fine implementation for doing  whats intended.. moving complete object states between VM instances.  Its not intended as a general comm mechanism.  Its not desigedn for that.  It has a lot of over-head buitl in to make it do what it IS desigend to do well, regardless of what differences have ocurred in the environment between VM instances.

Got a question about Java and game programming?  Just new to the Java Game Development Community?  Try my FAQ.  Its likely you'll learn something!

http://wiki.java.net/bin/view/Games/JeffFAQ
Offline crazyc94

Senior Newbie




I like cheese


« Reply #19 - Posted 2005-11-28 03:24:03 »

I noticed this thread earlier today, and thought that it may somewhat pertain to this discussion (more about GC and networking than Serialization):

http://www.java-gaming.org/forums/index.php?topic=1107.0

There's 4 chapters about networking an application, and and appedix on GC (letter C).

Just thought this may inspire a different approach, or get a better insight about GC.  Wink

Quack!  I'm a duck!

"Or make your own RationalNumber class (unless you need irrational numbers, then you're screwed )." - shmoove
Offline CommanderKeith
« Reply #20 - Posted 2005-11-28 15:14:14 »

Quote
Okay, maybe I am misunderstanding you.

Are you telling me you have done nothing to the encoding and *only*modified the decoiding logic?

What happens if the existing object is not of the right version? How are you dealign with mismatched SerialVersionUIDs ??

Jeff, you’ve got to read the code I posted.  The whole SS process has nothing to do with regular Serialization.  I borrow none of their code and I use none of their classes.  Indeed, I tried, but its all locked up in private methods and fields.  There are no SUID codes or anything.  To see how it works, just look at my code, its very short and simple.

Quote
I agree it's a foolish way in the wider sense, but it has considerable advantages in terms of simplicity to code against and to get up and running with a game with.

Thanks.  I’ve heard it being called 'Agile' programming - since you can change your game objects as you go without having to modify your communication mechanism.  The default write and readSS methods of those game objects implementing SSObject (or extending SSAdapter) allow for this since the fields they write aren't hard-coded.  This method allows you to run your game over the network before you’ve fully built it (or even planned how it will work >> lowers design time and costs).  The SS streams are good because after you’ve settled on a final design, you can make the process a lot more efficient by over-riding the default write and reads methods (this avoids the default methods’ Reflection API calls to get and set the fields).

Quote
Not so much "for a special purpose" as "not intended to be a high-performance system". I'd say it's a poor implementation done in minimal time and effort just enough to provide a basic service (nothing wrong with that - efficient use of development resources).It's not like the optimised Math.* methods, it's more like autoboxing - it provides the functionality at bare-bones performance. If you want better, pay for it or do it yourself.

The SS streams may not be quite as quick as custom byte packets, but the SS process is as simple, quick and elegant as possible while staying flexible and general (as far as I can limitedly see) .   I must repeat that the SS streams have nothing to do with regular Serialization, they extend the DataIn/OutputStreams, just the ones your custom binary packets would have been constructed from.

Quote
In modern VMs pooling generally is a net-loss v. the eden space  with regards to short-lived obejcts,.

So I think you are likely creating yourself problems here ratehr then solving them.

I have to pool the objects so they can be recycled, or else we will create new ones just like regular Serialization >> wasteful constructors and GC problems.

Quote
As I said before, if you find a need to pool arboitrary objects then you are holding onto short lived obejcst too long.  Which means you need to revist your app architecture.

The objects that are deserialized need to be held onto at least until they are fully painted to the screen, which is probably long enough to be pushed into the VM’s retirement-home space.  This needs to happen for any dumb-client architecture so it’s unavoidable and that’s why normal Serialization is unsuitable (as well as the more important disappearing references problem).

I'm about to try to get the clients in my game to think for themselves - ie run their own game world so GC problems and graphical smoothness can be taken care of by the client on its own.  I'll try to use the SS streams, if they are suited, to coordinate the server's game world with that of the clients, and I'll let you know how it goes.

If any more insightful people like yourselves could look at the code and suggest any improvements that can boost performance or functionality - I'd love to hear it.

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CopyableCougar4 (23 views)
2014-08-22 19:31:30

atombrot (34 views)
2014-08-19 09:29:53

Tekkerue (30 views)
2014-08-16 06:45:27

Tekkerue (28 views)
2014-08-16 06:22:17

Tekkerue (18 views)
2014-08-16 06:20:21

Tekkerue (27 views)
2014-08-16 06:12:11

Rayexar (65 views)
2014-08-11 02:49:23

BurntPizza (41 views)
2014-08-09 21:09:32

BurntPizza (31 views)
2014-08-08 02:01:56

Norakomi (41 views)
2014-08-06 19:49:38
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!