为什么如此高效?解密kryo各个数据类型的序列化编码机制,强
用过dubbo的开发人员 , 在替换序列化时都会根据“经验”来选kryo为序列化框架 , 其原因是序列化协议非常高效 , 超过java原生序列化协议 , hessian2协议 , 那kryo为什么高效呢?
序列化协议 , 所谓的高效 , 通常应该从两方面考虑:
- 序列化后的二进制序列大小 。
- 序列化 , 反序列化的速率 。
序列化:将各种数据类型(基本类型 , 包装类型 , 对象 , 数组 , 集合)等序列化为字节序列的过程 。
反序列化:将字节转换为各种数据类型(基本类型 , 包装类型 , 对象 , 数组 , 集合) 。
java中定义的数据类型所对应的序列化器在Kryo的构造函数中构造 , 其代码截图:
文章插图
接下来将详细介绍java常用的数据类型的序列化机制 , 即Kryo是如何编码二进制流 。
1 , DefaultSerializers $ IntSerializerint类型序列化
static public class IntSerializer extends Serializer { {setImmutable(true); } public void write (Kryo kryo, Output output, Integer object) {output.writeInt(object, false); } public Integer read (Kryo kryo, Input input, Class type) {return input.readInt(false); }}
1.1整数---> byte [](序列化)输出#writeIntpublic int writeInt (int value, boolean optimizePositive) throws KryoException { // @1return writeVarInt(value, optimizePositive);// @2}
代码@ 1:布尔值optimizePositive , 是否优化绝对值 。 如果optimizePositive:false , 将对值进行移位运算 , 如果是正数 , 则存放的替换原值的变量 , 如果是负数的话 , 放置的位移绝对值的形式变量一 , 其算法为:value =http://kandian.youth.cn/index/(值<< 1)^(值>> 31) , 在反序列化时 , 通过该算法恢复原值:((结果>>> 1) ^-(result&1)) 。代码@ 2:调用writeVarInt , 采用变长编码来存储int而不是固定4字节 。
输出#writeVarInt
public int writeVarInt (int value, boolean optimizePositive) throws KryoException {if (!optimizePositive) value = http://kandian.youth.cn/index/(value << 1) ^ (value>> 31);if (value >>> 7 == 0) {// @1require(1);buffer[position++] = (byte)value;return 1;}if (value >>> 14 == 0) {// @2require(2);buffer[position++] = (byte)((valuebuffer[position++] = (byte)(value >>> 7);return 2;}if (value >>> 21 == 0) {require(3);buffer[position++] = (byte)((valuebuffer[position++] = (byte)(value >>> 7 | 0x80);buffer[position++] = (byte)(value >>> 14);return 3;}if (value >>> 28 == 0) {require(4);buffer[position++] = (byte)((valuebuffer[position++] = (byte)(value >>> 7 | 0x80);buffer[position++] = (byte)(value >>> 14 | 0x80);buffer[position++] = (byte)(value >>> 21);return 4;}require(5);buffer[position++] = (byte)((valuebuffer[position++] = (byte)(value >>> 7 | 0x80);buffer[position++] = (byte)(value >>> 14 | 0x80);buffer[position++] = (byte)(value >>> 21 | 0x80);buffer[position++] = (byte)(value >>> 28);return 5; }
其思想是采用变长字节来存储int类型的数据 , int在java是固定4字节 , 由于在应用中 , 一般使用的int数据都不会很大 , 4个字节中 , 存在高位字节全是存储0的情况 , 故kryo为了减少在序列化流中的大小 , 尝试按需分配 , kryo采用1-5个字节来存储int数据 , 为什么int类型在JAVA中最多4个字节 , 为什么变长int可能需要5个字节才能存储呢?这与变长字节需要标志位有关 , 从而根据代码来解释kryo关于int序列化字节的编码规则 。代码@ 1:值>>> 7 == 0 , 一个数字 , 无符号右移(高位补0)7位后为0 , 说明该数字只占一个字节 , 并且高同轴必须为0 , 也就是该数字的范围在0-127(2 ^ 7 -1) , 对于字节的高位 , 低位的说明如下:
文章插图
如果该值范围为0-127则使用1个字节存储int即可 。 在操作缓存区时buffer [position ++] =(byte)value , 需要向输出的缓存区申请1个字节的空间 , 然后进行赋值 , 并返回本次申请的存储空间 , 对于require方法在Byte [] , String序列化时重点讲解 , 包含缓存区的扩容 , 输出与输出流结合使用时的相关机制 。
代码@ 2:值>>> 14 == 0 , 如果数字的范围在0到2 ^ 14-1范围之间 , 则需要两个字节存储 , 这里为什么是14 , 其首要是 , 对于一个字第中的8位 , kryo需要将高位用来当标记位置 , 使用标识是否还需要读取下一个字节 。 1:表示需要 , 0:表示不需要 , 也就是一个数据的结束 。 在变长int存储过中 , 一个字节8位kryo可用于存储数字有效位为7位 。
- 看不上|为什么还有用户看不上华为Mate40系列来看看内行人怎么说
- 设置|iPhone拍照小技巧:保留常用设置更高效
- 制药领域|为什么AI制药这么火,为什么是现在?
- 手机壳里头|为什么要在手机壳里面夹钱?10个有9个不懂,我才知道大有讲究
- 短视频|全球最火APP?抖音爆火背后离不开这几剂“猛药”为什么抖音能够这么火?
- 电商快递|包邮不香吗,为什么还有人加49元让小哥穿西装专车送快递?
- 团队|为什么项目管理非常重要?
- 猫腻|为什么拼多多上商品价格那么便宜还包邮?有什么猫腻?看完明白了
- 加拿大|上演戏剧性一幕!iPhone12最新售价确定,苹果也没想到降价如此快
- 刷机|前几年满大街的“刷机”服务去哪里了,为什么大家都不爱刷机了?