如何加快 Java VM (JVM) 的启动时间?断续器其他调优高深

2022-09-01 01:05:08

我正在运行启动多个JVM进程的测试。与在 JVM 中运行的实际测试的时间相比,JVM 的摘要启动时间非常重要。如何加快速度?

我已经使用了“-client”选项,这确实有帮助,但没有我想要的那么多。有没有其他方法,比如说预加载一堆JVM并以某种方式重用它们?


答案 1

如果你确实想重用JVM,“不知何故”可能是Nailgun。Nailgun 保持 JVM 运行,然后使用轻量级本机客户端启动特定类并处理控制台 io。这对于运行小型命令行 Java 实用程序是很好的,但是由于它重用相同的 JVM,因此可以累积状态。

为了解决状态累积问题,以运行多个 JVM 为代价,另一种选择是 Drip。Drip 使用正确的类路径和其他 JVM 选项保留了新的 JVM,因此您可以在需要时快速连接和使用它,然后将其丢弃。Drip 对 JVM 选项进行哈希处理,并将有关如何连接到 JVM 的信息存储在以哈希值作为其名称的目录中。


答案 2

JVM启动性能可以通过多种方式提高:CDS,直接向上调整,CPU固定和jlink(从JDK 9开始)可以是不错的选择。AOT(JDK 9,仅限Linux)有一些粗糙的边缘,但可以进行调整以帮助小型应用程序。

断续器

类数据共享是在 1.5 中为客户端 VM 开发的,但自从适用于 HotSpot 的所有变体(自 8 以来的所有 GC)以来,它已得到很大改进,从而在启用时显著提高了启动性能。

CDS 始终在 32 位 JRE 客户端安装时启用,但可能需要执行一些手动步骤才能在其他位置启用:

  1. 运行以生成 CDS 共享存档java -Xshare:dump
  2. 添加到命令以确保它被使用-Xshare:auto

其他调优

虽然实际上可能会或可能不会做任何事情(许多系统上的JVM不附带客户端VM - 实际上没有9个),但有很多方法可以调整HotSpot服务器JVM,使其表现得更像客户端VM:-client

  • 仅使用 C1(客户端)编译器:-XX:TieredStopAtLevel=1
  • 使用尽可能少的编译器线程:-XX:CICompilerCount=1
  • 使用单线程串行 GC:-XX:+UseSerialGC
  • 限制堆使用量(特别是在大型系统上),例如-Xmx512m

这应该足以促进小型短期运行的应用程序的启动,但可能会对峰值性能产生非常不利的影响。当然,您可以通过禁用您可能不使用的功能来进一步,例如(禁用一些使用MXBeans和jvmstat检索的运行时信息)。-XX:-UsePerfData

高深

  • jlink 是 Java 9 中提供的新工具,它允许您构建自定义运行时映像。如果控制台应用程序仅使用 JDK 模块的一小部分,则可以使自定义运行时变得非常小,这可以进一步缩短启动时间。一个最小的映像,仅包含 java.base 模块,并且可能会将启动时间提高约 10-20 毫秒,具体取决于硬件和其他调整:$JAVA_HOME/bin/jlink --add-modules java.base --module-path $JAVA_HOME/jmods --output jbase

  • (仅限 Linux)Java 9 引入了一个实验性的 AOT 编译器,它可以用来帮助应用程序更快地启动,并且花费更少的周期。开箱即用,它可能会减慢立即启动的速度(因为AOT代码是一个共享库,它增加了自己的I / O开销,不支持串行GC..),但是通过仔细调整,我们已经看到它将小型应用程序的启动时间缩短了15-30%。jaotc

  • CPU 固定:在大型系统上,我们已经看到了套接字之间的缓存一致性流量所产生的影响,绑定到单个 CPU 节点可以大大缩短启动时间。在Linux上,类似的东西应该可以做到这一点。numactl --cpunodebind=0 $JAVA_HOME/bin/java ...

总而言之,我们已经能够在短短35ms(JDK 9 GA)内执行最少的应用程序。JDK10分支已经进行了各种启动优化,我现在看到的数字低至28ms。


推荐