Saturday, 23 November 2013

Java 7 Performance Issue with XMLEncoder/XMLDecoder classes

Objective

To demonstrate Java 7 performance issue with XMLEncoder/XMLDecoder classes.

Environment

 JDK 7  or JRE 7

Issue

 If you have used XMLEncoder and XMLDecoder classes in your application and moved to Java 7 from Java 5 or 6 then it is worth notice the performance degrade in your application.
The following program can be run in different Java version and performance difference can be observed:

Program:
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

import javax.swing.JButton;

public class TestXMLEncode {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        XMLEncoder e = new XMLEncoder(new BufferedOutputStream(
                new FileOutputStream("Test1.xml")));
        e.writeObject(createObject());
        e.close();

        if (args.length > 0) {
            xmlSize = Integer.parseInt(args[0]);
        }

        if (args.length > 1) {
            numThread = Integer.parseInt(args[1]);
        }

        System.out.println("Size: " + xmlSize + ", Threads: " + numThread);

        for (int i = 0; i < 10; i++) {
            run();
        }
    }

    static int numThread = 1;
    static int xmlSize = 100;

    static Object createObject() {
        JButton[] o = new JButton[xmlSize];
        for (int i = 0;i < o.length; i++) {
            o[i] = new JButton("Hello, world");
        }
        return o;
    }

    static void run() {
        final long start = System.currentTimeMillis();
        final Object o = createObject();

        ExecutorService executorService = Executors.newFixedThreadPool(numThread);

        try {
            List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
            for (int i = 0; i < 2000 / xmlSize; i++) {
                tasks.add(new Callable() {
                    public Object call() {
                        byte[] data = encode(o);
                        decode(data);
                        return null;
                    }
                });
            }
            executorService.invokeAll(tasks);

            System.out.println("Finished: " + (System.currentTimeMillis() - start) + " ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static byte[] encode(Object o) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            XMLEncoder e = new XMLEncoder(bos);
            e.writeObject(o);
            e.close();

            return bos.toByteArray();
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }
    }

    private static void decode(byte[] data) {
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(data);
            XMLDecoder d = new XMLDecoder(bis);

            d.readObject();
            d.close();
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }
    }

}

Test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0-u40-unofficial" class="java.beans.XMLDecoder">
 <object class="javax.swing.JButton">
  <string>Hello, world</string>
 </object>
</java>

Observation

We have also faced thread hung issue by moving to Java 7 and observed that a thread hungs at XMLEncoder class causing other many thread to be blocked at XMLEncoder/XMLDecoder calls.
We have opened a ticket with Oracle and they did acknowledge the issue, and probably they will fix this issue with some patch or so.

Thank You!