Skip to content

fastjson 2.0.54版本发布,性能进一步提升

Latest
Compare
Choose a tag to compare
@wenshao wenshao released this 12 Jan 02:14
· 21 commits to main since this release

这又是一个性能优化Bug修复的版本更新版本,大家按需升级。

1. 性能优化

这个版本的性能优化包括:

1.1 使用SWAR(SIMD Within A Register)技巧来优化序列化字符串的性能

序列化时,写字符串检测是否存在特别字符是一个性能关键点,这个版本使用SWAR(SIMD Within A Register)的技巧来做快速检测。如下

package com.alibaba.fastjson2;
class JSONWriterUTF8 {
    protected final long byteVectorQuote;

   JSONWriterUTF8(Context ctx) {
        // " -> 0x22, ' -> 0x27
        this.byteVectorQuote = this.useSingleQuote ? 0x2727_2727_2727_2727L : 0x2222_2222_2222_2222L;
    }

    public void writeStringLatin1(byte[] value) {
        final long vecQuote = this.byteVectorQuote;
        int i = 0;
        final int upperBound = (value.length - i) & ~7;
        // 这里一次检测8个byte是否存在特别字符
        for (; i < upperBound; i += 8) {
            if (containsEscaped(IOUtils.getLongLittleEndian(value, i), vecQuote)) {
                break;
            }
        }
        // ...
    }

    static boolean containsEscaped(long v, long quote) {
        /*
          for (int i = 0; i < 8; ++i) {
            byte c = (byte) data;
            if (c == quote || c == '\\' || c < ' ') {
                return true;
            }
            data >>>= 8;
          }
          return false;
         */
        long x22 = v ^ quote; // " -> 0x22, ' -> 0x27
        long x5c = v ^ 0x5c5c5c5c5c5c5c5cL;

        x22 = (x22 - 0x0101010101010101L) & ~x22;
        x5c = (x5c - 0x0101010101010101L) & ~x5c;

        return ((x22 | x5c | (0x7F7F_7F7F_7F7F_7F7FL - v + 0x1010_1010_1010_1010L) | v) & 0x8080808080808080L) != 0;
    }
}

https://github.com/alibaba/fastjson2/blob/2.0.54/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java#L484

1.2 优化在JDK 16+的readString性能

在JDK 16+的版本下,使用StringLatin1.indexOfChar方法加速扫描特殊字符,优化readString的性能。这个算法来自 wycst 的贡献。

class JSONReaderASCII {
    static final int ESCAPE_INDEX_NOT_SET = -2;

    protected int nextEscapeIndex = ESCAPE_INDEX_NOT_SET;

    public String readString() {
            int slashIndex = nextEscapeIndex;
            if (slashIndex == ESCAPE_INDEX_NOT_SET || (slashIndex != -1 && slashIndex < offset)) {
                nextEscapeIndex = slashIndex = IOUtils.indexOfChar(bytes, '\\', offset, end);
            }
            if (slashIndex == -1 || slashIndex > index) {
                valueLength = index - offset;
                offset = index;
           // ...
    }
}

https://github.com/alibaba/fastjson2/blob/2.0.54/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java#L1445

1.3 int/long/float/double的读取写性能

优化的技巧是一次性读取两个数字,如下:

package com.alibaba.fastjson2;

class JSONReaderUTF8 {
    public final int readInt32Value() {
       // ...
        while (inRange
                && offset + 1 < end
                && (digit = IOUtils.digit2(bytes, offset)) != -1
        ) {
            // max digits is 19, no need to check inRange (result == MULT_MIN_100 && digit <= (MULT_MIN_100 * 100 - limit))
            if (inRange = (result > INT_32_MULT_MIN_100)) {
                result = result * 100 - digit;
                offset += 2;
            }
        }
    }
}
package com.alibaba.fastjson2.util;
class IOUtils {
    public static int digit2(byte[] bytes, int off) {
        short x = UNSAFE.getShort(bytes, ARRAY_BYTE_BASE_OFFSET + off);
        if (BIG_ENDIAN) {
            x = Short.reverseBytes(x);
        }
        int d;
        if ((((x & 0xF0F0) - 0x3030) | (((d = x & 0x0F0F) + 0x0606) & 0xF0F0)) != 0
        ) {
            return -1;
        }
        return ((d & 0xF) << 3) + ((d & 0xF) << 1)  // (d & 0xF) * 10
                + (d >> 8);
    }
}

https://github.com/alibaba/fastjson2/blob/2.0.54/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java#L3506

这个优化最初灵感源泉来自 https://github.com/wycst/wast 的 io.github.wycst.wast.json.JSONTypeDeserializer.NumberImpl#deserializeInteger所采用的算法,然后做了进一步的改进。

2. Issues

  1. 修复toJSONString实际可用空间小于预设的问题 #255
  2. 格式化输出支持使用空格代替Tab,新增两个JSONWriter.Feature为PrettyFormatWith2Space和PrettyFormatWith4Space
  3. 修复非法输入缺少第一个花括号{不报错的问题 #2592
  4. 增强识别枚举,原来不能识别toString的结果,新增识别toString的结果。 #2820
  5. JSONObject.to 支持Void.class和void.class返回null #2879
  6. 修复CSVWriter写入CSV数据超过 65536 个字节时报错 #2988
  7. 修复SeeAlso类型父类是Abstract类型时JVM Crash的问题 #2987
  8. 修复初始化JSONFactory某些场景会导致循环依赖导致死锁的问题 #2994
  9. 修复JSON.toJSON方法行为和JSON.toJSONString不一致的问题 #2981
  10. 增强对注释的支持 #2983
  11. 修复某些场景JSONWriter.Feature.WriteNulls导致Long/Double序列化结果为Null的问题 #3049
  12. 修复toJavaObject方法不能识别早期时间毫秒到LocalDateTime的转换问题 #3091
  13. 修复反序列化private Class结果和toJavaObject方法结果不一致的问题 #3134
  14. 增强fastjson 1.x的兼容性 #3208 #2739 # 3144 #3157
  15. 增强对Record的支持 #3090
  16. JSONPath支持使用path设置List中的对象 #3125
  17. 修复private Boolean类型字段使用valueFilter报错的问题 #3076
  18. 修复JDK 9+ writeStringEscaped某些场景数组越界报错 #3209
  19. 增加对Key为Map类型的反序列化支持 #3214
  20. JSON.parseObject方法在某些情况下反序列化编码出错的问题 #3223 #3219
  21. 支持修改useGsonAnnotation 配置 #3258
    fastjson2缺省是能识别Gson的Annotation的,这个可以通过接口或者JVM启动参数关闭
import com.alibaba.fastjson2.JSONFactory;

// 手工关闭
JSONFactory.setUseGsonAnnotation(false);

也支持通过JVM启动参数关闭

-Dfastjson2.useGsonAnnotation=false
  1. 修复错误格式没有及时报错的问题 #3260
  2. public首字母大写的字段,序列化重复key生成 #3220

MAVEN依赖配置

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.54</version>
</dependency>
  • android5针对优化版本
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.54.android5</version>
</dependency>
  • android8针对优化版本
    这个版本支持java.time和Optional
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.54.android8</version>
</dependency>
  • 1.x 兼容版本
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.54</version>
</dependency>
  • Spring 5 extension配置
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2-extension-spring5</artifactId>
    <version>2.0.54</version>
</dependency>
  • Spring 6 extension配置
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2-extension-spring6</artifactId>
    <version>2.0.54</version>
</dependency>

3. 相关链接