FastJson性能优化知多少

FastJson是一个近几年非常热门的第三方java库,它以它强大的功能和出色的性能表现而广为人知。那么,究竟为何FastJson能做到如此fast呢?它有什么秘诀?或者说,它做了哪些优化工作使得性能提升如此之多?本文从作者的理解出发,结合代码详细分析FastJson的性能优化方法和优秀的编程实践。

FastJson简介

首先来看看什么是FastJson。

引用自github [https://github.com/alibaba/fastjson]:

Fastjson is a Java library that can be used to  convert Java Objects into their JSON representation. It can also be used to  convert a JSON string to an equivalent Java object. Fastjson can work with  arbitrary Java objects including pre-existing objects that you do not have  source-code of.

简单总结下就是:

1. Fastjson是一个java库集合(server side and android client);

2. Fastjson可以将java对象和JSON字符串来回转换;

    Ps. JSON(JavaScript Object Notation, JavaScript对象表示法)是一种轻量级的数据交换格式。

3. Fastjson可以操作任何java对象,即使是一些预先存在的没有源码的对象。

Fastjson用途

Fastjson可以将java对象和JSON字符串来回转换,所以它能被用作:

1. 对象的序列化后存储(memcache, redis等)、传输(web, socket);

2. 接收数据后对象的还原即反序列化。

Fastjson的牛掰之处

几个主流json转换工具的功能性能对比(摘自网络):

几个常用序列化工具的处理速度对比(摘自网络):

从上面两个表的对比数据来看,

1.fastjson性能表现最好,解析速度最快,而且功能已经足够强大,推荐使用;

2.转换对象极其复杂情况下,可以考虑使用gson。

Fastjson提供什么功能/特性

以下几点摘自github [https://github.com/alibaba/fastjson]

1. Provide best performance in serverside and android client.

    提供服务器端、安卓客户端两种解析工具,性能表现业界最佳。

2. Provide simple toJSONString() andparseObject() methods to convert Java objects to JSON and vice-versa

    简单易用,调用toJSONString方法即可将对象转换成json字符串,parseObject方法则反过来将json字符串转换成对象。

3. Allow pre-existing unmodifiableobjects to be converted to and from JSON

    允许转换预先存在的无法修改的对象(只有class、无源代码)。

4. Extensive support of Java Generics

    Java泛型的广泛支持。

5. Allow custom representations forobjects

    允许对象的自定义表示、允许自定义序列化类。

6. Support arbitrarily complexobjects (with deep inheritance hierarchies and extensive use of generic types)

    支持任意复杂对象(具有深厚的继承层次和广泛使用的泛型类型)。

Fastjson的性能优化

那么接下来,我们分析下为什么Fastjson能做到这么快。分序列化和反序列化两个过程分析。

序列化

1. IdentityHashMap缓存各种序列化处理类,包括各种基本对象、集合对象、第三方对象、自定义对象,方便序列化处理类的快速查找、避免JavaBeanSerializer的反复创建。

更加详细代码请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/serializer/SerializeConfig.java

2. 使用ThreadLocal来存储序列化过程中不断append的字符串,减少内存分配和gc,从而提高性能。

3. 用类StringBuilder方式进行字符串操作,配合ThreadLocal实现线程安全的StringBuilder。

更加详细代码请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/serializer/SerializeWriter.java

4. 缺省启用sort field输出,为deserialize优化做准备。

具体为什么开启了排序的输出能够提升对象还原(反序列化)的效率,请查阅下面反序列化的“快速匹配”。

5. 使用asm高效反射,fastjson-asm基于objectweb asm 3.3.1改造,只保留必要的部分,不到2000行代码。具体代码可参考:https://github.com/alibaba/fastjson/tree/master/src/main/java/com/alibaba/fastjson/asm

反序列化

1. IdentityHashMap缓存各种反序列化处理类,包括基本对象、集合对象、第三方对象、自定义对象,方便反序列化类的快速查找、避免JavaBeanDeserializer的反复创建。代码与序列化的处理类缓存相似,具体请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java

2. 读取token基于预测。在反序列化一个json字符串时,下一个字符一般情况下是可以预估的。比如字符}之后最有可能出现的是“,”、“]”、“}”或者结束符,有计划、有预测地判断token将能提升不少性能。于是Fastjson在实现的时候写了这样一个函数:

更加详细的代码请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/JSONLexerBase.java

3. 快速匹配。在Fastjson反序列化过程中,有一个非常有用的效率改进方法是有序json的快速匹配。所谓有序json就是json字符串中的key是按照字符排序好了的。上面已经说过,Fastjson的序列化默认是按照key的顺序进行的,因此做反序列化时候,Fastjson采用一种优化算法,就是假设key/value的内容是有序的,读取的时候只需要做key的匹配,而不需要把key从输入中读取出来。通过这个优化,使得Fastjson在处理json文本的时候,少读取超过50%的token,这个是一个十分关键的优化算法。基于这个算法,使用asm实现,性能提升十分明显,超过300%的性能提升。例:

{"id":123,"name":"testJson","salary":11}

在上面例子看,虚线标注的三个部分是key,如果key_id、key_name、key_salary这三个key是顺序的,就可以做优化处理,这三个key不需要被读取出来,只需要比较就可以了。

这种算法分两种模式,一种是快速模式,一种是常规模式。快速模式是假定key是顺序的,能快速处理,如果发现不能够快速处理,则退回常规模式。保证性能的同时,不会影响功能。在这个例子中,常规模式需要处理13个token,快速模式只需要处理6个token。实现代码片段如下:

详细代码请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/deserializer/JavaBeanDeserializer.java

4. 使用asm高效反射

同上序列化的asm反射。

5. symbolTable算法缓存关键字,避免创建新的字符串对象。试想一下,假设一个json字符串中,有成千上万个同样的json对象的数组,那么在转换过程中,如果不对这些json对象中的key做缓存,将会存在成千上万个同样的字符串对象(值相同),显然这样会浪费极大的内存和性能。于是Fastjson写了一个SymbolTable类来缓存这些临时字符串符号变量。

更加详细的代码请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/SymbolTable.java

最后

除了性能优化之外,Fastjson还有许多编程思想和实践是值得我们去学习的,只要用心去研究和挖掘,必定能学到很多能够学以致用东西。当然,也只有认真去学习了并尝试在平时项目开发过程中运用,才能够真正提升自己的代码水平。后期有机会再给大家分享下Fastjson在ASM高效反射和泛型支持上的独具匠心之处,请大家拭目以待。J

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容