博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Kryo 为什么比 Hessian 快
阅读量:6914 次
发布时间:2019-06-27

本文共 5953 字,大约阅读时间需要 19 分钟。

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://rmncl.baihongyu.com/

你可能感兴趣的文章
Incomplete types-不完全类型
查看>>
eclipse maven build、maven clean、maven install和maven test的区别 精析
查看>>
阿里云 Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR invalid password
查看>>
哈哈,找到一本好书。
查看>>
git使用命令, 特别:git checkout -b a 与 git branch a区别
查看>>
Asp.net网站如何播放Flv视频
查看>>
Windtalkers 风语者
查看>>
mountmust
查看>>
如何判断一个String字符是否在string[]数组里
查看>>
[zz]hdfs-over-ftp安装
查看>>
iOS学习:UILabel和sizeWithFont方法
查看>>
《人生的智慧》第一章 基本的划分
查看>>
ecshop商品颜色尺寸仿淘宝选择功能教程
查看>>
AJAX实用教程——开篇
查看>>
数据库插入数据返回当前主键ID值方法
查看>>
浅谈三层架构
查看>>
Linux下使用openssl生成证书
查看>>
java设计优化-享元模式
查看>>
Android 获取文件大小
查看>>
linux删除或隐藏命令历史记录history
查看>>