Java 序列化反序列化对比

3次阅读

共计 5330 个字符,预计需要花费 14 分钟才能阅读完成。

Java 序列化工具对比,对比以下序列化工具对数据的存储大小以及计算耗时:

JDK 1.8
Hessian 4.0.60
Kryo 4.0.2
Protostuff:1.6.0

版本依赖
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.0.2</version>
</dependency>

<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.60</version>
</dependency>

<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.6.0</version>
</dependency>

<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.6.0</version>
</dependency>
测试代码
对 100000 个 User 进行序列化以及反序列化操作,输出操作时间以及各个工具序列化后累计的数据的长度:
/**
* 序列化器对比
* Created by Captain on 06/03/2019.
*/
public class SerializerUtil {

private static Kryo kryo = new Kryo();

/**
* JDK 序列化
*/
public static byte[] serializable(Object obj) {
if (obj == null) {
return null;
}
if (obj instanceof String) {
return ((String) obj).getBytes();
}
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
}
return null;
}

/**
* JDK 反序列化
*/
public static Object unserializable(byte[] bytes){
ByteArrayInputStream bais = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* kryo 反序列化
*/
public static Object unserializableKryo(byte[] bytes){
if (bytes == null) {
return null;
}
try {
// 反序列化
Input input = new Input(new ByteArrayInputStream(bytes));
Object obj = kryo.readClassAndObject(input);
input.close();
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* kryo 序列化
*/
public static byte[] serializableKryo(Object obj){
if (obj == null) {
return null;
}
if (obj instanceof String) {
return ((String) obj).getBytes();
}
try {
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output output = new Output(baos);
kryo.writeClassAndObject(output, obj);
output.flush();
output.close();
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* hessian 序列化
*/
public static byte[] serializableHessian(Object obj){
ByteArrayOutputStream byteArrayOutputStream = null;
HessianOutput hessianOutput = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
hessianOutput = new HessianOutput(byteArrayOutputStream);
hessianOutput.writeObject(obj);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
hessianOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

/**
* hessian 反序列化
*/
public static Object unserializableHessian(byte[] bytes){
ByteArrayInputStream byteArrayInputStream = null;
HessianInput hessianInput = null;
try {
byteArrayInputStream = new ByteArrayInputStream(bytes);
// Hessian 的反序列化读取对象
hessianInput = new HessianInput(byteArrayInputStream);
return hessianInput.readObject();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
byteArrayInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
hessianInput.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

/**
* protostuff 序列化
*/
public static <T> byte[] serializableProtostuff(T obj){
try {
RuntimeSchema schema = RuntimeSchema.createFrom(obj.getClass());
return ProtostuffIOUtil.toByteArray(obj, schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
} catch (Exception e){
e.printStackTrace();
return null;
}
}

/**
* protostuff 反序列化
*/
public static Object unserializableProtostuff(byte[] bytes, Class clazz){
RuntimeSchema schema = RuntimeSchema.createFrom(clazz);
Object obj = schema.newMessage();
ProtostuffIOUtil.mergeFrom(bytes, obj, schema);
return obj;
}

public static void main(String[] args) {

final int OBJECT_COUNT = 100000;
User user = new User();

long sum = 0;
long start = System.currentTimeMillis();
for (int i = 0 ; i <= OBJECT_COUNT ; i++){
user.setId(i);
user.setName(“Captain” + i);
user.setAge(18 + i);
byte[] bytes = serializable(user);
sum += bytes.length;
unserializable(bytes);
}
System.out.println(“JDK 1.8 序列化反序列化 -> 耗时 : ” + (System.currentTimeMillis() – start) + ” , 长度 : ” + sum);

long sum2 = 0;
long start2 = System.currentTimeMillis();
for (int i = 0 ; i <= OBJECT_COUNT ; i++){
user.setId(i);
user.setName(“Captain” + i);
user.setAge(18 + i);
byte[] bytes = serializableKryo(user);
sum2 += bytes.length;
unserializableKryo(bytes);
}
System.out.println(“Kryo 4.0.2 序列化反序列化 -> 耗时 : ” + (System.currentTimeMillis() – start2) + ” , 长度 : ” + sum2);

long sum3 = 0;
long start3 = System.currentTimeMillis();
for (int i = 0 ; i <= OBJECT_COUNT ; i++){
user.setId(i);
user.setName(“Captain” + i);
user.setAge(18 + i);
byte[] bytes = serializableHessian(user);
sum3 += bytes.length;
unserializableHessian(bytes);
}
System.out.println(“Hessian 4.0.60 序列化反序列化 -> 耗时 : ” + (System.currentTimeMillis() – start3) + ” , 长度 : ” + sum3);

long sum4 = 0;
long start4 = System.currentTimeMillis();
for (int i = 0 ; i <= OBJECT_COUNT ; i++){
user.setId(i);
user.setName(“Captain” + i);
user.setAge(18 + i);
byte[] bytes = serializableProtostuff(user);
sum4 += bytes.length;
unserializableProtostuff(bytes, User.class);
}
System.out.println(“Protostuff 1.6.0 序列化反序列化 -> 耗时 : ” + (System.currentTimeMillis() – start4) + ” , 长度 : ” + sum4);
}
}
测试结果
JDK 1.8 序列化反序列化 -> 耗时 : 2970 , 长度 : 21989111
Kryo 4.0.2 序列化反序列化 -> 耗时 : 451 , 长度 : 5472470
Hessian 4.0.60 序列化反序列化 -> 耗时 : 1397 , 长度 : 7888970
Protostuff 1.6.0 序列化反序列化 -> 耗时 : 706 , 长度 : 2155925

工具
序列化后数据长度
耗时 ms

JDK 1.8
21989111
2970

Kryo 4.0.2
5472470
451

Hessian 4.0.60
7888970
1397

Protostuff 1.6.0
2155925
706

初步结论
耗时:JDK > Hessian > Protostuff > Kryo 数据长度:JDK > Hessian > Kryo > Protostuff
从测试结果来看,序列化工具 Protostuff 以及 Kryo 在耗时及存储上看均优于 JDK 以及 Hessian,相应的可以提供更高的计算性能以及更少的存储空间,选型过程中应当优先考虑。其次,衡量性能与存储,可根据场景选取 Protostuff 或 Kryo。

正文完
 0