这项研究的目标是探索JIT(即时编译)和AOT(提前编译)策略之间的性能差异,并理解它们各自的优缺点。我们不是要声称某一种语言更慢或更糟。
在我们的测试中,使用JIT编译的HotSpot JVM 23展现了更好的结果。而用Clang 18编译的C++、使用native-image编译的GraalVM 23、以及带有-Xcomp标志的HotSpot JVM 23表现较差。我们试图理解为什么会这样,如果可能的话,还想找到提高C++版本性能以匹配Java JIT编译结果的方法。
我们的基准测试比较了Java中简单小型哈希表(map)的实现与C++中逐行等效的实现。我们尽力保证两个实现的一致性。这个目标不是比较标准库中的哈希表实现(java.util.HashMap和std::unordered_map),因为它们当然是用不同的源代码实现的。
基准测试创建一个有20,000个桶的哈希表,并插入2,000,000个对象。我们插入一次,清空map然后再次插入,以利用哈希表的内部对象池。换句话说,第一次插入时,对象将在堆上分配。第二次插入时,对象将重用来自内部对象池的对象。
处理测量的Bench类在两种语言中应该也是等效的。
有鉴于这些细节,有人了解为什么C++ map实现会比Java map实现慢吗?我们有没有忽视某些东西或C++实现的某些方面可以进一步优化?也许有些Clang优化选项我们应该探索?
编辑(@petercordes补充详细描述基准测试内容,并与OP讨论以说明其中一个目标。
C++版本的编写方式使其可以编译成与JVM为Java版本JIT的类似机器代码。如何使Java执行与C++版本相同的机器操作但更快呢?
(编辑者注[@petercordes]: 我已单步执行Hotspot JVM生成的机器代码,确实主循环是链表的线性搜索,使用32位压缩引用对比clang++使用原生指针。通过GDB中断JVM,通常RIP指向代码花费大部分时间的地方。clang++ -O3 … -m32更快,但不仅仅是32位指针,Java对象仍然至少有24字节,而不仅仅是12个字节用于2个引用+一个int。可能与分配模式和缓存未命中相关,因为Java在循环内运行更多机器指令

最低0.47元/天 解锁文章
597

被折叠的 条评论
为什么被折叠?



