Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Into the mist of serialization myths

Performance myth: serialVersionUID improves Java serialization performance

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone

June 27, 2003

QDoes setting the serialVersionUID class field improve Java serialization performance?

AI 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:

  • They use coarse-grained timers like 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 results

  • They do not discard timings obtained from initial runs of their test code (see "Watch Your HotSpot Compiler Go" for why this is important)


To 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.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Archived Discussions (Read only)
Subject
. Forum migration complete By AthenAdministrator
. Forum migration update By AthenAdministrator
. Uniqueness By Anonymous
Resources