转载

Java 序列化反序列化对比

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。

原文  https://segmentfault.com/a/1190000018418736
正文到此结束
Loading...