JAVA

java序列化总结

2019-03-23  本文已影响0人  多关心老人

为什么需要序列化

序列化要考虑的因素

常见序列化方式

kryo目前的bug

性能和字节大小对比

SerializeBenchmarkTest3测试类,对几种序列化方式进行了测试:
测试数据:

private Person getPerson() {
        Person person = new Person();
        person.setId(123L);
        person.setName("你好啊");
        person.setMarried(true);
        person.setAge(22);
        person.setDigits(Arrays.asList(1L, 3L, 100L));
        Map<String, Double> scoreMap = new LinkedHashMap<>();
        scoreMap.put("chinese", 90d);
        scoreMap.put("english", 80.5d);
        person.setScores(scoreMap);
        Book book = new Book();
        book.setId(99L);
        book.setName("代码大全");
        book.setPrice(56.00d);
        person.setBook(book);

        int friendsCount = 1000;
        List<Person> friends = new ArrayList<>(friendsCount);
        for (int i = 0; i < friendsCount; i++) {
            Person friend = new Person();
            friend.setId(Long.valueOf(i));
            friend.setName(String.valueOf("我的朋友" + i));
            friend.setMarried(i % 2 == 0 ? true : false);
            friends.add(friend);
        }
        person.setFriends(friends);
        return person;
    }

test1方法测试了序列化后自己大小和md5,测试结果如下:

2019-03-23 15:22:04,916 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.jdkPerformance(54) - jdk序列化后长度:52797, 前后长度一致:true, md5一致:true,对象equals:true
2019-03-23 15:22:05,226 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.jsonPerformance(71) - json序列化后长度:59457, 前后长度一致:true, md5一致:true,对象equals:true
2019-03-23 15:22:05,309 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.hessian2Performance(88) - hessian2序列化后长度:26124, 前后长度一致:false, md5一致:false,对象equals:false
2019-03-23 15:22:05,380 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.hessianLitePerformance(105) - hessian-lite序列化后长度:26144, 前后长度一致:false, md5一致:false,对象equals:true
2019-03-23 15:22:05,661 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.kryoPerformance(122) - kryo序列化后长度:28101, 前后长度一致:true, md5一致:true,对象equals:true
2019-03-23 15:22:05,696 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.fstPerformance(139) - fst序列化后长度:33839, 前后长度一致:true, md5一致:true,对象equals:true

由于Person类继承了Human类,2个类都有同名属性id,hessian2在序列化的时候存在bug导致丢失数据,奇怪的是hessian-lite虽然解决了这个bug,但是前后序列化字节长度却不相等。
从上面结果可以看出,在小数据量场景下,hessian2及hessian-lite在体积上占有小优势,kryo、fst次之,jdk和json最差。

然后对上面的数据做10000次序列化和反序列化,结果如下:

14次YGC
13.658: [GC (Allocation Failure) [PSYoungGen: 682646K->233K(691200K)] 686763K->4350K(2089472K), 0.0018965 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2019-03-23 15:31:22,073 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.jdkPerformance(61) - jdk序列化、反序列化10000次耗时13699

9次YGC
19.258: [GC (Allocation Failure) [PSYoungGen: 687902K->318K(693248K)] 692530K->4946K(2091520K), 0.0006095 secs] [Times: user=0.06 sys=0.00, real=0.00 secs] 
2019-03-23 15:31:27,321 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.jsonPerformance(78) - json序列化、反序列化10000次耗时5245

5次YGC
24.824: [GC (Allocation Failure) [PSYoungGen: 689776K->121K(694784K)] 694539K->4909K(2093056K), 0.0007943 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2019-03-23 15:31:32,671 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.hessian2Performance(95) - hessian2序列化、反序列化10000次耗时5349

11次YGC
35.886: [GC (Allocation Failure) [PSYoungGen: 694368K->64K(696320K)] 699315K->5011K(2094592K), 0.0073285 secs] [Times: user=0.05 sys=0.00, real=0.01 secs] 
2019-03-23 15:31:43,688 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.hessianLitePerformance(112) - hessian-lite序列化、反序列化10000次耗时11017


3次YGC
39.634: [GC (Allocation Failure) [PSYoungGen: 694880K->64K(696832K)] 700003K->5203K(2095104K), 0.0007231 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2019-03-23 15:31:48,061 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.kryoPerformance(129) - kryo序列化、反序列化10000次耗时4373


3次YGC
43.816: [GC (Allocation Failure) [PSYoungGen: 694945K->193K(696832K)] 700308K->5556K(2095104K), 0.0007227 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2019-03-23 15:31:51,626 WARN  [main] c.y.o.s.SerializeBenchmarkTest3.fstPerformance(146) - fst序列化、反序列化10000次耗时3564

jvm参数:-Xms2g -Xmx2g -XX:+PrintGCTimeStamps -XX:+PrintGCDetails

可以看出fst最快,kryo次之,json、hessian2速度还不错,但是hessian-lite和jdk基本上一样慢。

最佳实践


序列化工具类:

static MzKryoPool<Kryo> kryoPool = new MzKryoPool<Kryo>(100);
    static FSTConfiguration fst = FSTConfiguration.createDefaultConfiguration();

    public static <T> byte[] serializeWithJdk(T object) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(4096);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            byte[] bytes = byteArrayOutputStream.toByteArray();
            objectOutputStream.close();
            return bytes;
        } catch (IOException e) {
            throw new OperationException("serialize with jdk fail: " + e.getMessage(), e);
        }
    }

    public static Object deserializeWithJdk(byte[] bytes) {
        try {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            Object object = objectInputStream.readObject();
            objectInputStream.close();
            return object;
        } catch (ClassNotFoundException | IOException e) {
            throw new OperationException("deserialize with jdk fail: " + e.getMessage(), e);
        }
    }

    public static byte[] serializeWithJson(Object object) {
        return JSON.toJSONBytes(object);
    }

    public static <T> T deserializeWithJson(byte[] bytes, Class<T> cls) {
        return JSON.parseObject(bytes, cls);
    }

    public static byte[] serializeWithHessian2(Object object) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(4096);
            Hessian2Output hessianOutput = new Hessian2Output(byteArrayOutputStream);
            hessianOutput.startMessage();
            hessianOutput.writeObject(object);
            hessianOutput.completeMessage();
            hessianOutput.close();
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            throw new OperationException("serialize with hessian2 fail: " + e.getMessage(), e);
        }
    }

    public static Object deserializeWithHessian2(byte[] bytes) {
        try {
            Hessian2Input hessian2Input = new Hessian2Input(new ByteArrayInputStream(bytes));
            hessian2Input.startMessage();
            Object o = hessian2Input.readObject();
            hessian2Input.completeMessage();
            hessian2Input.close();
            return o;
        } catch (IOException e) {
            throw new OperationException("deserialize with hessian2 fail: " + e.getMessage(), e);
        }
    }

    public static byte[] serializeWithHessianLite(Object object) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(4096);
            com.alibaba.com.caucho.hessian.io.Hessian2Output hessian2Output = new com.alibaba.com.caucho.hessian.io.Hessian2Output(byteArrayOutputStream);
            hessian2Output.startMessage();
            hessian2Output.writeObject(object);
            hessian2Output.completeMessage();
            hessian2Output.close();
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            throw new OperationException("serialize with hessian-lite fail: " + e.getMessage(), e);
        }
    }

    public static Object deserializeWithHessianLite(byte[] bytes) {
        try {
            com.alibaba.com.caucho.hessian.io.Hessian2Input hessian2Input = new com.alibaba.com.caucho.hessian.io.Hessian2Input(new ByteArrayInputStream(bytes));
            hessian2Input.startMessage();
            Object o = hessian2Input.readObject();
            hessian2Input.completeMessage();
            hessian2Input.close();
            return o;
        } catch (IOException e) {
            throw new OperationException("deserialize with hessian-lite fail: " + e.getMessage(), e);
        }
    }

    public static byte[] serializeWithKryo(Object obj) {
        Kryo kryo = kryoPool.obtain();
        //initial 4k, max 10M
        try (Output output = new Output(4096, 10 * 1024 * 1024);) {
            kryo.writeClassAndObject(output, obj);
            return output.toBytes();
        } catch (Exception e) {
            throw new OperationException("deserialize with kryo fail: " + e.getMessage(), e);
        } finally {
            kryoPool.free(kryo);
        }
    }

    public static Object deserializeWithKryo(byte[] bytes) {
        Kryo kryo = kryoPool.obtain();
        try (Input input = new Input(bytes)) {
            return kryo.readClassAndObject(input);
        } catch (Exception e) {
            throw new OperationException("deserialize with kryo fail: " + e.getMessage(), e);
        } finally {
            kryoPool.free(kryo);
        }
    }

    public static byte[] serializeWithFst(Object obj) {
        return fst.asByteArray(obj);
    }

    public static Object deserializeWithFst(byte[] bytes) {
        return fst.asObject(bytes);
    }
上一篇 下一篇

猜你喜欢

热点阅读