• Kryo 为什么比 Hessian 快


    Kryo 是一个快速高效的Java对象图形序列化框架,它原生支持java,且在java的序列化上甚至优于google著名的序列化框架protobuf。由于 protobuf需要编写Schema文件(.proto),且需静态编译。故选择与Kryo类似的序列化框架Hessian作为比较来了解一下Kryo 为什么这么快。

    序列化的过程中主要有3个指标:

    1、对象序列化后的大小
    一个对象会被序列化工具序列化为一串byte数组,这其中包含了对象的field值以及元数据信息,使其可以被反序列化回一个对象

    2、序列化与反序列化的速度
    一个对象被序列化成byte数组的时间取决于它生成/解析byte数组的方法

    3、序列化工具本身的速度
    序列化工具本身创建会有一定的消耗。

    从序列化后的大小入手:

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Simple implements java.io.Serializable{ 
     private String name; 
     private int age; 
      
      
     public String getName() { 
       return name; 
     
      
      public void setName(String name) { 
        this.name = name; 
      
       
      public int getAge() { 
        return age; 
      
       
      public void setAge(int age) { 
        this.age = age; 
      
       
      static Simple getSimple() { 
        Simple simple = new Simple(); 
        simple.setAge(10); 
        simple.setName("XiaoMing"); 
        return simple; 
      
    }

    Kryo序列化:

    1
    2
    3
    4
    5
    6
    7
    Kryo kryo = new Kryo(); 
    kryo.setReferences(false); 
    kryo.setRegistrationRequired(false); 
    kryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); 
    output.setOutputStream(new FileOutputStream("file.bin")); 
    kryo.writeClassAndObject(output, Simple.getSimple()); 
    output.flush();

    查看序列化后的结果:



    红色部分:对象头,01 00代表一个未注册过的类

    黑色部分:对象所属的class的名字(kryo中没有设定某个字段的结束符,对于String这种不定长的byte数组,kryo会在其 最后一个byte字节加上x70,如类名最后一位为e,其askii码为x65,在其基础上加x70,即为E5)

    绿色部分:表示这个对象在对象图中的id。即simple对象在对象图中的id为01.

    蓝色部分:表示该类的field。其中02 14中14表示int数值10(映射关系见表1),02和绿色部分的01意思是一样的,即 10这个int对象在对象图中的id为02。以此类推,03表示对象图中的第三个对象,即XiaoMing这个String, 同样其最后一位byte被加了x70。

    Hessian序列化:

    1
    2
    HessianOutput hout = new HessianOutput(new FileOutputStream("hessian.bin")); 
    hout.writeObject(Simple.getSimple()); <span></span><span></span>

    查看序列化后的结果: 

     

    红色部分: 对象头

    黑色部分: 对象所属的类名(类名的askii码)

    紫色部分: 字节类型描述符,表示之后的字节属于何种类型,53表示String,49表示int,等等

    绿色部分: 字节长度描述符,用于表示后面的多少个字节是表示该字节组的

    白色部分: field实际的类型的byte值

    蓝色部分: filed实际的value

    7A: 结束符

    从序列化后的字节可以看出以下几点:

    1、Kryo序列化后比Hessian小很多。(kryo优于hessian)

    2、由于Kryo没有将类field的描述信息序列化,所以Kryo需要以自己加载该类的filed。这意味着如果该类没有在kryo中注册,或者该类是第一次被kryo序列化时,kryo需要时间去加载该类(hessian优于kryo)

    3、由于2的原因,如果该类已经被kryo加载过,那么kryo保存了其类的信息,就可以很快的将byte数组填入到类的field中,而hessian则需要解析序列化后的byte数组中的field信息,对于序列化过的类,kryo优于hessian。

    4、hessian使用了固定长度存储int和long,而kryo则使用的变长,实际中,很大的数据不会经常出现。(kryo优于hessian)

    5、hessian将序列化的字段长度写入来确定一段field的结束,而kryo对于String将其最后一位byte+x70用于标识结束(kryo优于hessian)

    总上所述:

    kryo为了保证序列化的高效性,会加载需要序列化的类,这会带来一定的消耗。可以理解为kryo本身的消耗。由于这点消耗从而可以保证序列化后的大小(避免不必要的源数据)比较小和快速的反序列化。

    通过变长的int和long值保证这种基本数据类型序列化后尽量小

    通过最后一位的特殊操作而非写入长度来标记字段的范围

    本篇未涉及到的地方还有:

    使用开源工具reflectasm进行反射而非java本身的反射

    使用objenesis来创建无默认构造函数的类的对象

    由于kryo目前只支持Java,所以官方文档也没有给出它序列化所用的kryo grammer,默认支持以下十种。见表一

    表一:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    # the number of milliseconds since January 1, 1970, 00:00:00 GMT
    date       ::= x01 x00 <the number of milliseconds since January 1, 1970, 00:00:00 GMT>
     
               # boolean true/false
    boolean ::= x02 x01 # true
                  ::= x02 x00   # false
                
               # 8-bit binary data
    byte       ::= x03 <binary-data>  # binary-data 
     
               # char
    char       ::= x04 x00 <binary-data>  # binary-data 
         
               # short
    short   ::= x05 [x00-x7F] [x01-xFF] # 0 to 32767
           ::= x05 [x80-xFF] [x01-xFF]  # -23768 to -1
                
               # 32-bit signed integer( + x02 when increment)
    int       ::= x06 x01 [x00-x7E]                                 # 0 to 63
               ::= x06 x01 [x80-x9E] [x04-xFF]                                  # 64 to 4095
               ::= x06 x01 [xA0-xBE] [x00-xFF] [x01-xFF]                    # 4096 to 1048575
               ::= x06 x01 [xC0-xDE] [x00-xFF] [x00-xFF] [x01-xFF]              # 1048576 to 268435455
           ::= x06 x01 [xE0-xFE] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x07]    # 268435456 to 2147483647
               ::= x06 x01 [x01-x7F]                                    # -1 to -64
               ::= x06 x01 [x81-x9F] [x04-xFF]                                  # -65 to -4096
               ::= x06 x01 [xA1-xBF] [x00-xFF] [x01-xFF]                    # -4097 to -1048576
               ::= x06 x01 [xC1-xDF] [x00-xFF] [x00-xFF] [x01-xFF]              # -1048577 to -268435456
               ::= x06 x01 [xE1-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x07]    # -268435457 to -2147483648
                
               # 64-bit signed long integer ( +x02 when incerment)
    long       ::= x07 x01 [x00-x7E]                                                                                        # 0 to 63
               ::= x07 x01 [x80-x8E] [x08-xFF]                                                                              # 64 to 2047
               ::= x07 x01 [x90-x9E] [x00-xFF] [x01-xFF]                                                                    # 2048 to 524287
               ::= x07 x01 [xA0-xAE] [x00-xFF] [x00-xFF] [x01-xFF]                                                          # 524288 to 134217727
               ::= x07 x01 [xB0-xBE] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                                                # 134217728 to 34359738367
           ::= x07 x01 [xC0-xCE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                                      # 34359738368 to 8796093022207
               ::= x07 x01 [xD0-xDE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                            # 8796093022208 to 2251799813685247
           ::= x07 x01 [xE0-xEE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                  # 2251799813685248 to 576460752303423487
           ::= x07 x01 [xF0-xFE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x0F]        # 576460752303423488 to 9223372036854775807
           ::= x07 x01 [x01-x7F]                                                                                        # -1 to -64
               ::= x07 x01 [x81-x8F] [x08-xFF]                                                                              # -65 to -2048
               ::= x07 x01 [x91-x9F] [x00-xFF] [x01-xFF]                                                                    # -2049 to -524288
               ::= x07 x01 [xA1-xAF] [x00-xFF] [x00-xFF] [x01-xFF]                                                          # -524289 to -134217728
               ::= x07 x01 [xB1-xBF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                                                # -134217729 to -34359738368
           ::= x07 x01 [xC1-xCF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                                      # -34359738369 to -8796093022208
           ::= x07 x01 [xD1-xDF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                            # -8796093022209 to -2251799813685248
           ::= x07 x01 [xE1-xEF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]                  # -2251799813685249 to -576460752303423488
           ::= x07 x01 [xF1-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x0F]        # -576460752303423489 to -9223372036854775808
       
               # float/Float
    float      ::= x08 x01 <floatToInt>
     
               # double/Double
    double     ::= x09 x01 <doubleToLong>
     
               # String
    String     ::= x0A x01 x82 <utf8-data>                                                                    # data.length()=1
               ::= x0A x01 <utf8-data.subString(0,data.length()-2)> <utf8-data.charAt(data.length-1)>+x70   # data.length()>1
     
                # The class not registered in kryo
    Object  ::= x01 x00 <(string)className> <(byte)id> <(Object)objectFieldValue ordered by fieldName>

    via http://x-rip.iteye.com/blog/1555344

  • 相关阅读:
    WPF项目学习.一
    AtCoder Beginner Contest 210 A~D 题解
    P7715 「EZEC-10」Shape 题解
    P6216 回文匹配 题解
    字符串学习笔记
    #2742. 「JOI Open 2016」销售基因链
    树状数组学习笔记
    2021 省选游记
    AtCoder Beginner Contest 196 E
    AtCoder Regular Contest 113 A~D题解
  • 原文地址:https://www.cnblogs.com/duanxz/p/4494398.html
Copyright © 2020-2023  润新知