Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
June 27, 2003
Does setting the serialVersionUID class field improve Java serialization performance?
I have heard this performance "tip" from several colleagues and keep running across it in various Java forums. In this Java Q&A installment, we discover that it is mostly an urban legend.
The question refers to the following problem: when deserializing an object of class X, Java must establish that the incoming data is sufficiently compatible with the local class X definition. This is accomplished by comparing the so-called stream-unique identifiers (SUIDs) of the incoming and local class
definitions. If the two SUIDs do not match, deserialization fails. If you don't do anything, the SUID is computed as a hash
of various class elements: class name, implemented interfaces, declared nonstatic, nontransient fields, declared nonprivate
methods, and so on. But it is also possible to take control of this value by declaring the following class field:
private static final long serialVersionUID = <some value>;
The actual value assigned to serialVersionUID does not matter as long as you remember to change it with every serialization-incompatible change to the class.
Besides giving you explicit control over class versioning, placing an explicit SUID value in the serialVersionUID field supposedly saves many CPU cycles during serialization. That's the folklore, in any case. Let's see if it's really true.
A few published performance analyses discovered "surprising" performance savings related to serialVersionUID optimization. Some of them suffer from several shortcomings:
System.currentTimeMillis(), necessitating long repeat loops in code and raking up tons of temporary objects on the heap, possibly causing garbage collection
to bias all resultsTo get better results, I put together the following simple test class:
public class SerialVersionUIDTest
{
public static void main (final String [] args)
throws Exception
{
final DecimalFormat format = new DecimalFormat ("#.000");
// Create a couple of timers to keep track of object
// serialization/deserialization:
s_wtimer = TimerFactory.newTimer ();
s_rtimer = TimerFactory.newTimer ();
// This is my test object:
final TestClass testobj = new TestClass ();
// ITimer/perftest() warmup:
for (int i = 0; i < 3000; ++ i)
{
perftest (testobj);
s_wtimer.getDuration ();
s_wtimer.reset ();
s_rtimer.reset ();
}
final int repeats = 500;
final double [] durations = new double [repeats];
final Object [] holder = new Object [repeats];
for (int r = 0; r < repeats; ++ r)
{
Object clone = perftest (testobj);
holder [r] = clone; // Retain this reference to minimize GC activity
durations [r] = s_wtimer.getDuration () + s_rtimer.getDuration ();
s_wtimer.reset ();
s_rtimer.reset ();
}
// Compute the average:
double avg = 0.0;
for (int i = 0; i < repeats; ++ i) avg += durations [i];
avg /= repeats;
// Sort to get percentile metrics:
Arrays.sort (durations);
System.out.println ("[min/avg/95th percentile, ms] min: "
+ format.format (durations [0])
+ ", avg: " + format.format (avg)
+ ", 95%: " + format.format (durations [(95 * repeats)/100]));
}
/*
* This is the actual test method. It clones 'obj' by in-memory serialization.
* Only the costs of writeObject()/readObject() are tallied.
*/
private static Object perftest (final Object obj)
throws IOException, ClassNotFoundException
{
s_out.reset ();
ObjectOutputStream oout = new ObjectOutputStream (s_out);
s_wtimer.start ();
oout.writeObject (obj);
s_wtimer.stop ();
ObjectInputStream in = new ObjectInputStream (new ByteArrayInputStream (s_out.toByteArray ()));
s_rtimer.start ();
final Object result = in.readObject ();
s_rtimer.stop ();
return result;
}
private static ITimer s_wtimer, s_rtimer;
private static final ByteArrayOutputStream s_out = new ByteArrayOutputStream (32 * 1024);
} // End of class
Regular Java Q&A column readers should see familiar patterns above. I used the high-resolution timer developed in "My Kingdom for a Good Timer!." Even though the guts of that library are Java Native Interface (JNI) code, I nevertheless warm up the accompanying ITimer byte code via the usual loop whose repeat count is higher than the client HotSpot's native compilation threshold (again,
see "Watch Your HotSpot Compiler Go"). My test method is perftest(), which is warmed up within the same loop: I am interested in my runtime's steady state, not what happens on the first invocation.
The SerialVersionUIDTest version you can download also cleans up the JVM heap before commencing the timing loop.
Archived Discussions (Read only)