性能技术
首先,它取决于您所谈论的 哪个 JVM,因为有多个 - 但我假设您的意思是 Oracle HotSpot(无论如何,其他顶级 JVM将使用类似的技术)。
对于那个 JVM,来自 HotSpot 内部 wiki 的this list 提供了一个很好的开始(子页面详细介绍了一些更有趣的技术)。如果您只是在寻找技巧清单,请访问 wiki has that too,尽管要理解它们,您可能需要在 Google 上搜索各个术语。
并非所有这些都是最近实施的,但一些大的已经实施(范围检查省略、转义分析、超词优化)——至少对于“最近”的松散定义。
接下来,让我们看一下 C/C++ 与 Java 的相对性能图,以及为什么上述技术有助于缩小差距,或者在某些情况下实际上赋予 Java 和固有的优势,而不是原生编译语言。
Java 与 C/C++
在高层次上,优化是您在任何体面的 C 和 C++ 等本机语言编译器中看到的东西的混合,以及减少 Java/JVM 特定功能和安全性影响所需的东西检查,例如:
- 转义分析(在某种程度上)减轻了对象的无堆栈分配
- 内联缓存和类层次结构分析,可缓解“每个函数都是虚拟的”
- 消除范围检查,从而减轻“每个数组访问都经过范围检查”
这些 JVM 特定* 优化中的许多仅有助于使 JVM 与本地语言平起平坐,因为它们正在解决本地语言不必处理的障碍。然而,一些优化是静态编译语言无法管理的(或者在某些情况下只能通过配置文件引导的优化来管理,这种情况很少见,而且无论如何都必须一刀切):
- 只动态内联最热门的代码
- 根据实际分支/开关频率生成代码
- 动态生成 CPU/指令集感知代码(甚至是编译代码后发布的 CPU 功能!)1
- 省略从未执行的代码
- 注入与应用程序代码交错的预取指令
- 安全指向支持的整个技术系列
大家的共识似乎是,Java 生成的代码通常在速度上与中等优化级别的优秀 C++ 编译器相似,例如 gcc -O2,尽管很大程度上取决于确切的基准。像 HotSpot 这样的现代 JVM 往往在低级数组遍历和数学方面表现出色(只要竞争的编译器没有向量化 - 这很难被击败),或者在竞争代码执行相似数量分配时具有大量对象分配的场景中(JVM 对象分配 + GC 通常比 malloc 快),但是当典型 Java 应用程序的内存损失是一个因素时,堆栈分配被大量使用,或者向量化编译器或内在函数向本机代码倾斜时,就会下降。
如果您搜索 Java 与 C 的性能,您会发现很多人都解决了这个问题,他们的严谨程度各不相同。这是first one I stumbled across,它似乎显示了gcc 和HotSpot 之间的大致联系(即使在这种情况下为-O3)。 This post 和链接的讨论可能是一个更好的开始,如果您想了解单个基准如何通过每种语言的多次迭代、相互跨越 - 并显示双方优化的一些限制。
*并不是真正特定于 JVM - 大多数也适用于其他 安全 或 CLR 等托管语言
1 随着新指令集(尤其是 SIMD 指令,但有 others)以某种频率发布,这种特殊的优化变得越来越重要。自动向量化可以大幅加速某些代码,虽然 Java 在这方面的速度已经很慢,但它们至少是 catching up 一点点。