Yes, the default serialization strategy can get big really quick...
writeObject recursively writes
all the Serializable objects in the tree, so in the worst case it has the potential to write out almost the entire heap, if your Serializable objects are all cross-referencing each other!

For starters, you should make sure you mark as
transient any attributes/members that you do not want to serialize, or that should not be serialized, in your Serializable objects.
You might want to investigate writeReplace() and readResolve(), to use light-weight "proxy" serializations. Those two methods, under the
Serializable interface, let you change the objects that actually get serialized/deserialized.
We are doing that for our MMORTS game, which results in 1) much-much faster serialization, and 2) much-much smaller packet size,
without sacrificing the advantages of Serialization.
It took a few days to get it set up right, but the end result is pretty good! We use a tag inside the "proxy" object to specify the "actual" class, and a lightweight HashMap to store the attributes. Plus a version number to handle backwards compatibility issues. We use the
same code to do serialize/deserialize mapping, database mapping and XML mapping. Whenever we add/remove an attribute to a class, we just update the mapping info and we're done - no additional code needed!
One thing to look out for - especially if you are using JMS, which can do serialization under the covers - is to make sure that your serialized "proxy" objects can get -re-serialized without corruption. And vice-versa on re-deserialization.
As always, the default Java implementation gets you pretty far, but the next-better version requires some more work!
I hope that helps!
--Brad