我以前使用过 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 中,这会导致性能问题,因此需要一个替代方案。