Pages

Monday, November 10, 2008

ObjectOutputStream : Writing the same object over and over again!

Well, Well, Well.. You know, I was just writing a very tiny socket application in Java and was stuck for a long time on 'Writing Objects from server to Client!'. I myself can not believe that. With so many samples around on the Internet, I was still stuck. A pretty interesting problem I would like to share. I have a server writing objects to its clients. But the client is always receiving the same object. The first one. The code snippet is given below:

....
....
....
os = new ObjectOutputStream(socket.getOutputStream());
....
....
....

if(toBeSentData.shouldConsume()){
    Object object = toBeSentData.get();
    if(null != object){
        os.writeObject(object);
        os.flush();
    }
}

You can see, I am flushing the output stream. I debugged through the writeObject code, to find out that my Object was not written at all. Some handle was written. Specifically, in method private void writeObject0(Object obj, boolean unshared) throws IOException, the snippet is present below.

// handle previously written and non-replaceable objects
int h;
if ((obj = subs.lookup(obj)) == null) {
    writeNull();
    return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
    writeHandle(h);
    return;
} else if (obj instanceof Class) {
    writeClass((Class) obj, unshared);
    return;
} else if (obj instanceof ObjectStreamClass) {
    writeClassDesc((ObjectStreamClass) obj, unshared);
    return;
}


The handles.lookup(obj) was never returning -1. So, the problem is some sort of caching(Not exactly caching) I understood. The only guy who had explained this was Qusay H. Mahmoud in his December 2001 post about Advanced Socket Programming at http://java.sun.com/developer/technicalArticles/ALT/sockets/
I really thank him for that, else I would have been stuck with the problemo for god knows How long!!

I will just copy the last part of the article here. This is what gave me the solution.

Object Serialization Pitfall

When working with object serialization it is important to keep in mind that the ObjectOutputStream maintains a hashtable mapping the objects written into the stream to a handle. When an object is written to the stream for the first time, its contents will be copied to the stream. Subsequent writes, however, result in a handle to the object being written to the stream. This may lead to a couple of problems:

    * If an object is written to the stream then modified and written a second time, the modifications will not be noticed when the stream is deserialized. Again, the reason is that subsequent writes results in the handle being written but the modified object is not copied into the stream. To solve this problem, call the ObjectOutputStream.reset method that discards the memory of having sent an object so subsequent writes copy the object into the stream.
    * An OutOfMemoryError may be thrown after writing a large number of objects into the ObjectOutputStream. The reason for this is that the hashtable maintains references to objects that might otherwise be unreachable by an application. This problem can be solved simply by calling the ObjectOutputStream.reset method to reset the object/handle table to its initial state. After this call, all previously written objects will be eligible for garbage collection.

The reset method resets the stream state to be the same as if it had just been constructed. This method may not be called while objects are being serialized. Inappropriate invocations of this method result in an IOException.

Just call the os.reset(); after flush. It worked like a charm for me!!

No comments:

Post a Comment