Java 序列化工具对比,对比以下序列化工具对数据的存储大小以及计算耗时:
- JDK 1.8
- Hessian 4.0.60
- Kryo 4.0.2
- Protostuff:1.6.0
版本依赖
com.esotericsoftware
kryo
4.0.2
com.caucho
hessian
4.0.60
io.protostuff
protostuff-core
1.6.0
io.protostuff
protostuff-runtime
1.6.0
测试代码
对 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 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。