I have a client and server communicating via Spring remoting (using Java Serialization) over a proprietary messaging system. My server returns large objects so my Spring remoting implementation splits the serialized object byte array into blocks, and sends multiple messages. The client waits for all the response messages for a given request and eventually calls the method below to the deserialize the byte arrays into the resultant object.
protected Object deserialize(List<byte[]> blocks) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream(blocks.size() * blockSize);
for (byte[] b : blocks) {
os.write(b, 0, b.length);
}
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream objInputStream = new ObjectInputStream(is);
return objInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
This works perfectly. However, its very memory heavy. Assuming an object in memory is very roughly the same size as its serialized byte array in memory, I end up with something like 3 times the size of my object in memory:
- the
List<byte[]>containing the blocks - the
ByteArrayOutputStreamcontaining concatenated byte array (and possibly another becauseByteArrayOutputStream.toByteArray()copies the array). - the resulting Object
Once this method returns all the arrays can be GC’d, but during this method call there’s a big spike in memory usage.
So, to my question: Is there a way that I can create a blocking byte input stream that I can append the byte arrays to as I receive them? ObjectOutputStream would (in a separate thread) read available bytes, then block until more bytes were written, and continue until the object was fully deserialized. In this way, I don’t ever have to have the full concatenated byte array in memory. None of the standard stream implementations seem to fit, I can’t see how I’d use NIO to do this, and I’d rather not write my own stream implementation if there’s one out there that would suffice.
Many thanks,
Ian
implement your own input stream to lessen the array overhead
ofcourse you’ll should also override
read(byte[],int,int)as well for efficiency but this will work if a tad slowlyOr you can use the
PipedInputStreamandPipedOutputStreamcombo for what you really want. The input stream will block until it has something to read