java序列化方案對比
1、引言
目前移動客戶端應用程式上,需要將使用者內容持久化到裝置上,一般任何feed流應用,如微博、推特、新聞客戶端等都需要將內容做持久化操作,以便在記憶體回收後,再次進入程式能迅速恢復之前的內容。另外如一些視訊、音樂、購物等軟體,凡是收藏的視訊、歌曲、商品以及個人主頁等,也應將這些使用者私有的內容做序列化,以便無網進入時也能看到相關內容,並正常使用軟體。
陸陸續續使用和測試過一些Java序列化方案,這篇主要從Android客戶端應用程式的角度,並以速度、序列化檔案大小、實踐簡易性為主要考慮指標介紹並對比以下序列化方案。
2、JVM-Serializsers
(1)JVM-Serializsers使用介紹
Requirements:
- GNU Make 3.81+
- JDK 1.5+
To compile:
make
To run:
./run -help
具體步驟:
1.切到tcp原始碼目錄下
2.編譯原始碼:
3.執行測試案案例:
?1 |
./run -chart -include=kryo,fst-serialization,java-built-in,protobuf,hessian,json/google-gson/databind,xml/xstream+c,bson/mongodb,bson/jackson/databind,json/fastjson/databind,json/jackson/databind,thrift,avro-generic data/media.1.cks |
include引數代表要進行測試的序列化工具,當然前提是在jvm-serialization中的測試模型下已經構建完相應工具的測試用例。更多引數可通過./run -help看說明,如果帶上-chart引數,還會生成序列化效能資料的圖形對比。
4.執行結果:
表中引數介紹:
-
Total Time (“total”):建立一個物件,將其序列化成一個位元組陣列,然後再反序列化成一個物件。
-
Serialization Time (“ser”):建立一個物件,將其序列化成一個位元組陣列。
-
Deserialization Time (“deser+deep”):相比於序列化,反序列化更耗時。為了更公平的比較,jvm-serializers在反序列化測試時訪問了反序列化得到的物件的所有欄位(也就是deep的含義),因為部分工具反序列化時“偷懶”而沒有做足工作。
-
Serialized Size (“size”):序列化資料的大小,這個大小會依賴於使用的資料。
-
Serialization Compressed Size (“size+dfl”):使用java內建的DEFLATE(zlib)壓縮的序列化資料的大小。
-
Object Creation Time (“create”):物件建立耗時很短(平均100納秒)所以通常的比較沒什麼意義。不過,不同工具建立的物件在表現上會有不同。有的工具只是建立普通的java類,你可以直接訪問其欄位,而有的使用get/set方法,有的使用builder模式。
該工具還將這些資料通過google chart服務生成資料圖形對比圖:
圖2-1
5.測試環境
os:os x-10.9
jdk:java version "1.7.0_51"
mem:16G
cpu: 2.3 GHz Intel Core i7
更多在Android Runtime的測試見下文。
以上,已經可以利用強大的JVM-Serializsers工具來分析跟構建自己想測試的序列化工具了。
(2)Java序列化工具技術原理比較
-
Binary Formats & language-specific ones
JavaBuiltIn(java原生)、JavaManual(根據成員變數型別,手工寫)、FstSerliazation、Kryo
-
Binary formats-generic language-unspecific ones
-
JSON Format
-
JSON-like:
CKS (textual JSON-like format)、BSON(JSON-like format with extended datatypes)
JacksonBson、MongoDB
-
XML-based formats
java的序列化工具大致就可以分為以上幾類,簡單概括就分為二進位制binary和文字格式(json、xml)兩大類。
從圖2-1中可以較為明顯的看出,在速度的對比上一般有如下規律:
binary > textual
language-specific > language-unspecific
而textual中,由json相比xml冗餘度更低因此速度上更勝一籌,而json又bson這類textual serialization技術上更成熟,框架的選擇上更豐富和優秀。下面重點介紹下Kryo、fast-serialiation、fastjson、protocol-buffer
3、典型Java序列化工具分析
(1)Java原生序列化工具
Java本身提供的序列化工具基本上能勝任大多數場景下的序列化任務,關於其序列化機制,這篇文章很細緻的解釋了,值得一讀。Java自帶的序列化工具在序列化過程中需要不僅需要將物件的完整的class name記錄下來,還需要把該類的定義也都記錄下,包括所有其他引用的類,這會是一筆很大的開銷,尤其是僅僅序列化單個物件的時候。正因為java序列化機制會把所有meta-data記錄下來,因此當修改了類的所在的包名後,反序列化則會報錯。Java自帶序列化工具的效能問題總結如下:
-
一個single object的序列化會遞迴地,連同所有成員變數(instsnce variables)一起序列化了,這種預設機制很容易造成不必要的序列化開銷。
-
序列化和反序列化過程需要上面的這種機制去遞歸併用反射機制去尋找所有成員變數的資訊,另外如果沒定義自己serialVersionUID的話,那麼物件及其他變數都必須自己產生一個。上述過程開銷很大。
-
使用預設序列化機制,所有序列化類定義完整資訊都會被記錄下來,包括所有包名、父類資訊、以及成員變數
(2)優化過的Java序列化工具
kryo根據上述Java原生序列化機制的一些問題,對了很多優化工作,而且提供了很多serializer,甚至封裝了Unsafe型別的序列化方式,更多關於Unsafe型別的序列化方式,請參考這裡,需要注意的是,jdk1.7以後,預設關閉unsafe的類(sun.misc.Unsafe)包。更多kryo介紹參考kryo的wiki,這裡貼一下kryo的典型用法。其中CompatibeFieldSerializer就是預設提供的一系列serializer的一種,顧名思義就是一種成員變數上下相容的序列化工具,支援該類對成員變數的增刪。另外kryo更新比較活躍,問題修復很快。
?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 |
private static Kryo myKryo = new Kryo();
static
|