使用 JMH 找到最快的编码/解码 UTF-8 的方法
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2800+ 小伙伴加入学习 ,欢迎点击围观
我以前使用过 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 中,这会导致性能问题,因此需要一个替代方案。