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

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

1、对象序列化后的大小

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

2、序列化与反序列化的速度

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

3、序列化工具本身的速度

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

 

从序列化后的大小入手:

测试类:

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序列化:

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();

 查看序列化后的结果:

 

hyper架构和KS架构 kryo架构_对象图

 红色部分:对象头,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序列化:

HessianOutput hout = new HessianOutput(new FileOutputStream("hessian.bin"));  
 hout.writeObject(Simple.getSimple());

查看序列化后的结果:

hyper架构和KS架构 kryo架构_数组_02

红色部分: 对象头

 黑色部分: 对象所属的类名(类名的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值保证这种基本数据类型序列化后尽量小

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