使用 JMH 找到最快的编码/解码 UTF-8 的方法

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

我以前使用过 JMH,但这是我第一次使用 JMH 来解决生产问题。我对如何优化所涉及的代码有一些想法,但尝试与 JMH 的不同组合会带来显着的改进。

在此测试中,我将字符串编码为 UTF8 以引导内存,以便将其写入 TCP 套接字。我还需要通过 NIO SocketChannel.read 将数据写入直接内存并将其编码为 StringBuilder (可以重复使用)

测试

这些测试包括使用反射获取 String 和 StringBuilder 的底层数据结构以及使用 Unsafe 访问本机内存的组合。

令我惊讶的是,通过反射访问 String 似乎并不快,甚至可能更慢。对于较短的字符串,情况更糟,这表明使用反射的开销大于任何好处。

请参阅 encode_unsafeLoopCharA t 和 encode_unsafeLoopCharAt

另一个惊喜是通过反射访问 StringBuilder 确实有所不同。

请参见 decode_usingSimpleLoop decode_usingCharArray 访问底层 char[] 的速度提高了 4 倍以上。注意:这是一个明显的优化问题,未来的 Java 版本可能不会有这个问题。

所有结果


 Benchmark                                    Mode  Cnt         Score        Error  Units
DecodeMain.decode_fromUTF8                  thrpt   20   5395187.171 �  17525.486  ops/s
DecodeMain.decode_usingCharArray            thrpt   20   7967263.552 � 259148.327  ops/s
DecodeMain.decode_usingCharArrayAndAddress  thrpt   20  11644515.566 �  52786.179  ops/s
DecodeMain.decode_usingSimpleLoop           thrpt   20   1884355.264 �   3442.892  ops/s
EncodeMain.encode_simpleToUTF8              thrpt   20   5050422.611 �  31681.322  ops/s
EncodeMain.encode_unsafeLoopCharArray       thrpt   20  16837387.866 � 814047.308  ops/s
EncodeMain.encode_unsafeLoopCharAt          thrpt   20  18225151.521 � 132811.688  ops/s
EncodeMain.encode_unsafeLoopCharAtUnrolled  thrpt   20  13848365.955 � 102407.681  ops/s
EncodeMain.encode_usingSimpleLoop           thrpt   20   8868356.295 � 368546.131  ops/s
EncodeMain.encode_usingSimpleLoopUnrolled   thrpt   20   7077634.663 �  30359.636  ops/s

结论

将来此功能可能会内置到 JVM 中,但是可能有一些功能未内置到 JVM 中,这会导致性能问题,因此需要一个替代方案。

相关文章