美文网首页
使用kryo需注意的问题

使用kryo需注意的问题

作者: binecy | 来源:发表于2019-03-23 18:27 被阅读0次

    kryo的使用,经常可以在网上看到这样的例子

        private static Kryo kryo = new Kryo();
    
        public byte[] serialize(Object o) {
            Output output = new Output(new ByteArrayOutputStream());
            kryo.writeClassAndObject(output, o);
            byte[] bytes = output.toBytes();
            output.flush();
            output.close();
    
            return bytes;
        }
    
        public <T> T deserialize(byte[] bytes) {
            Input input = new Input(bytes);
            T o = (T)kryo.readClassAndObject(input);
            return o;
        }
    

    但这样实际有两个隐藏的问题。

    • Output output = new Output(new ByteArrayOutputStream());会导致缓冲区溢出
        public Output(OutputStream outputStream) {
            this(4096, 4096);
            if(outputStream == null) {
                throw new IllegalArgumentException("outputStream cannot be null.");
            } else {
                this.outputStream = outputStream;
            }
        }
    

    可以看到使用OutputStream构建Output时,缓冲区默认值和最大值都是4096。当遇到大对象,会缓冲区溢出,这是kryo会从开头重新写缓冲区,这样又导致另一个问题。

    kryo中序列化的类要注册一个id,kryo序列化时,会将该id+2写入结果开头,作为class的标识。
    kryo还提供了writeClassAndObject/readClassAndObject的方式,会将class的信息写入到结果字节中,读取时也会从字节中读取class信息,如果class标识为1,表示使用的是writeClassAndObject/readClassAndObject的方式。

    回到缓冲区溢出的问题,kryo从开头重新写缓冲区,会导致class标识被重写为其他值,当读取时,kryo会使用该错误的class标识查找对应的注册class,查找失败会抛出class未注册的异常:

    com.esotericsoftware.kryo.KryoException: Encountered unregistered class ID: -39
    

    因为缓冲区溢出导致抛出class未注册的异常,这个就非常有迷惑性了,需要对kryo机制有一定了解才能解决。

    • private static Kryo kryo = new Kryo();导致线程安全问题

    Kryo不是线程安全的,使用该静态的Kryo类会在多线程情况出现各种问题。
    为了避免频繁创建Kryo对象导致性能损耗,可以使用ThreadLocal或apache的commons-pool2连接池。

    kryo是性能较高的序列化工具,可用于dubbo或netty的序列化性能,拓展:
    使用Kryo的序列化方式提升Netty性能

    参考:
    Kryo简介及代码阅读笔记
    kryo序列化:默认bufferSize

    相关文章

      网友评论

          本文标题:使用kryo需注意的问题

          本文链接:https://www.haomeiwen.com/subject/vcasvqtx.html