Understanding Java Serialization: Limitations, Performance Comparison, and Alternative Frameworks
The article explains what object serialization is, why it is needed for persistence and network transmission, outlines the major drawbacks of Java's built‑in serialization—including lack of cross‑language support, poor performance, and large payloads—and compares it with a custom ByteBuffer approach while reviewing popular alternative serialization frameworks.
Serialization is the process of converting an object into a byte sequence for persistence or network transmission.
It is required when saving an object's state to a file or database, transmitting objects over sockets, or using RMI.
Java's native serialization suffers from three major problems: it cannot be decoded by other languages, its performance is far inferior to manual ByteBuffer encoding, and the resulting byte stream is several times larger than the original data.
A performance test compares Java's built‑in serialization with a custom ByteBuffer implementation. The test repeatedly serializes a simple UserInfo object 1,000,000 times, measuring elapsed time for each method.
import java.io.Serializable;
import java.nio.ByteBuffer;
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public byte[] codeC() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
byte[] value = this.name.getBytes();
buffer.putInt(value.length);
buffer.put(value);
buffer.putLong(this.id);
buffer.flip();
byte[] result = new byte[buffer.remaining()];
buffer.get(result);
return result;
}
public byte[] codeC(ByteBuffer buffer) {
buffer.clear();
byte[] value = this.name.getBytes();
buffer.putInt(value.length);
buffer.put(value);
buffer.putLong(this.id);
buffer.flip();
byte[] result = new byte[buffer.remaining()];
buffer.get(result);
return result;
}
} import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
public class MainTest {
public static void main(String[] args) throws Exception {
UserInfo info = new UserInfo();
info.setId(1L);
info.setName("Tom");
int loop = 100_0000;
ByteArrayOutputStream bout = null;
ObjectOutputStream out = null;
long start = System.currentTimeMillis();
for (int i = 0; i < loop; i++) {
bout = new ByteArrayOutputStream();
out = new ObjectOutputStream(bout);
out.flush();
out.close();
byte[] b = bout.toByteArray();
bout.close();
}
System.out.println("jdk serializable time : " + (System.currentTimeMillis() - start) + " ms");
System.out.println("------------------------------");
start = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocate(1024);
for (int i = 0; i < loop; i++) {
byte[] bytes = info.codeC(buffer);
}
System.out.println("ByteBuffer time : " + (System.currentTimeMillis() - start) + " ms");
}
}The benchmark results show that the custom ByteBuffer method is considerably faster and produces a much smaller byte array than Java's default serialization.
Because of these shortcomings, many open‑source serialization frameworks have emerged. The article briefly introduces Protobuf, Thrift, Jackson, Gson, and FastJson, comparing them on cross‑platform support, encoded size, efficiency, and ease of use.
Choosing the right framework based on these criteria can significantly improve system performance and reduce bandwidth consumption.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.