Java 为什么Jackson流式API很慢?

Java 为什么Jackson流式API很慢?,java,jackson,java-11,jmh,jackson-modules,Java,Jackson,Java 11,Jmh,Jackson Modules,根据Jackson流媒体API文档: 如果显式重写所有转换以使用流API而不是数据绑定,则可以将吞吐量提高30-40%;这不需要对实际生成的JSON进行任何更改 全文如下: 但是,根据我的基准测试,在最好的情况下,吞吐量提高了15-20%,对于编写复杂对象,吞吐量甚至降低了约23% 我做错什么了吗?为什么具有流式api的复杂对象的写操作比使用在流式api之上工作的ObjectMapper慢 非常有趣的是,Jackson流媒体性能的下降对于java11/12来说更为显著(与java11/12的24

根据Jackson流媒体API文档:

如果显式重写所有转换以使用流API而不是数据绑定,则可以将吞吐量提高30-40%;这不需要对实际生成的JSON进行任何更改

全文如下:

但是,根据我的基准测试,在最好的情况下,吞吐量提高了15-20%,对于编写复杂对象,吞吐量甚至降低了约23%

我做错什么了吗?为什么具有流式api的复杂对象的写操作比使用在流式api之上工作的ObjectMapper慢

非常有趣的是,Jackson流媒体性能的下降对于java11/12来说更为显著(与java11/12的24%相比,下降了约2%)

配置:

  • 8 CPU
  • 64 GB内存
  • 操作系统版本16.04.1 LTS(Xenial Xerus)
  • Docker版本18.03.0-ce,版本0520e24
JMH吞吐量结果:

  • 预热:10次迭代,每次10秒
  • 测量:10次迭代,每次10秒
  • 线程:1个线程,将同步迭代
  • 虚拟机选项:-XX:+UseG1GC-server-Xmx4096m-Xms4096m
  • 单位:行动组
复杂对象

json对象大小~52KB

普通对象

json对象大小~72B

结构:

//普通对象
公共体育课{
长id;
字符串名;
}
//复杂对象
公开课活动{
长id;
长运动ID;
字符串名;
日期开始时间;
布尔运算;
布尔AllowLiveBoting;
上市市场;
列出与会者名单;
}
公务舱市场{
长id;
长事件;
字符串名;
布尔运算;
布尔AllowLiveBoting;
双重价值;
整数优胜者;
列出跑步者名单;
}
公开课跑者{
长id;
长事件;
长期市场化;
长期活动参与者;
字符串名;
布尔撤回;
双重价值;
}
公开课活动参与者{
长id;
长事件;
字符串participantName;
字符串名称;
字符串trainerName;
整数;
}
代码

@基准测试
@基准模式(模式吞吐量)
public void complexJacksonStreamWrite(执行计划计划,黑洞)引发IOException{
Event=plan.getBigObjects();
ByteArrayOutputStream outputStream=新建ByteArrayOutputStream();
try(JSONG发电机)=
plan.getFactory().createGenerator(
outputStream,JsonEncoding.UTF8){
generator.writeStartObject();
generator.WriteEnumberField(“id”,event.getId());
//填充rest属性
generator.writeFieldName(“事件参与者”);
generator.WriteStarray();
对于(int i=0;i
如何跑步

爪哇8

docker run-it volkodav/JavaJackson基准:java8

爪哇11

docker run-it volkodav/JavaJackson基准:java11

爪哇12

docker run-it volkodav/java jackson基准:java12

源代码:


更新

在@Jom Vernee发表评论后,他建议设置ByteArrayOutputStream的大小-Jackson流式写入的性能提高了约10%

ByteArrayOutputStream outputStream = new ByteArrayOutputStream(60_000);
复杂

普通的


您是否尝试过预先调整输出流的大小?考虑到这两种方法在分配压力上的差异,我猜内部缓冲区的重新分配工作正在进行。初始大小仅为32字节,用完时会加倍,但在这种情况下必须复制内部缓冲区。是的,你有一个非常有效的观点!我应用了您的建议,性能提高了约10%,但仍然比ObjectMapper慢;(