Java 序列化工具对比,对比以下序列化工具对数据的存储大小以及计算耗时:
<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。