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!
Oracle has acknowledge the issue with following bug which already identified in Java 8:
ReplyDeletehttps://bugs.openjdk.java.net/browse/JDK-8028054