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);
}
}
}
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>
<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!