Kryo 爲何比 Hessian 快

Kryo 是一個快速高效的Java對象圖形序列化框架,它原生支持java,且在java的序列化上甚至優於google著名的序列化框架protobuf。因爲 protobuf須要編寫Schema文件(.proto),且需靜態編譯。故選擇與Kryo相似的序列化框架Hessian做爲比較來了解一下Kryo 爲何這麼快。 java

序列化的過程當中主要有3個指標: 數組

一、對象序列化後的大小
一個對象會被序列化工具序列化爲一串byte數組,這其中包含了對象的field值以及元數據信息,使其能夠被反序列化回一個對象 框架

二、序列化與反序列化的速度
一個對象被序列化成byte數組的時間取決於它生成/解析byte數組的方法 函數

三、序列化工具自己的速度
序列化工具自己建立會有必定的消耗。 工具

從序列化後的大小入手: 測試

測試類: ui

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

?
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表明一個未註冊過的類 google

黑色部分:對象所屬的class的名字(kryo中沒有設定某個字段的結束符,對於String這種不定長的byte數組,kryo會在其 最後一個byte字節加上x70,如類名最後一位爲e,其askii碼爲x65,在其基礎上加x70,即爲E5) spa

綠色部分:表示這個對象在對象圖中的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: 結束符

從序列化後的字節能夠看出如下幾點:

一、Kryo序列化後比Hessian小不少。(kryo優於hessian)

二、因爲Kryo沒有將類field的描述信息序列化,因此Kryo須要以本身加載該類的filed。這意味着若是該類沒有在kryo中註冊,或者該類是第一次被kryo序列化時,kryo須要時間去加載該類(hessian優於kryo)

三、因爲2的緣由,若是該類已經被kryo加載過,那麼kryo保存了其類的信息,就能夠很快的將byte數組填入到類的field中,而hessian則須要解析序列化後的byte數組中的field信息,對於序列化過的類,kryo優於hessian。

四、hessian使用了固定長度存儲int和long,而kryo則使用的變長,實際中,很大的數據不會常常出現。(kryo優於hessian)

五、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
相關文章
相關標籤/搜索