我正在运行一些启动多个JVM进程的测试。相比于在JVM内部运行的实际测试时间,JVM的总体启动时间相当重要。我该如何加快速度?
我已经使用了“-client”选项,这确实有所帮助,但并不如我所期望的那样。是否还有其他方法,比如预加载一堆JVM并以某种方式重用它们?
我正在运行一些启动多个JVM进程的测试。相比于在JVM内部运行的实际测试时间,JVM的总体启动时间相当重要。我该如何加快速度?
我已经使用了“-client”选项,这确实有所帮助,但并不如我所期望的那样。是否还有其他方法,比如预加载一堆JVM并以某种方式重用它们?
JVM启动性能可以通过多种方式进行优化:CDS、直接调整、CPU绑定和jlink(自JDK 9以来)都是不错的选择。AOT(JDK 9,仅限Linux)存在一些问题,但可以进行调整以帮助小型应用程序。
类数据共享在1.5年为客户端VM开发,但自那时以来已经大大改进,可以在所有HotSpot变体上工作(自8以来所有GC),当启用时可大大提高启动性能。
CDS在32位JRE客户端安装中始终启用,但可能需要一些手动步骤才能在其他位置启用:
java -Xshare:dump
生成CDS共享存档-Xshare:auto
以确保它被使用虽然-client
可能会有所作为,也可能不会做任何事情(实际上自9以来,许多系统的JVM都没有提供客户端VM),但有许多方法可以调整HotSpot服务器JVM,使其行为更像客户端VM:
-XX:TieredStopAtLevel=1
-XX:CICompilerCount=1
-XX:+UseSerialGC
-Xmx512m
这应该足以提高小型短期运行应用程序的启动速度,但可能对峰值性能产生非常负面的影响。您当然可以进一步禁用您可能不使用的功能,例如-XX:-UsePerfData
(禁用某些可通过MXBeans和jvmstat检索的运行时信息)。
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编译器,jaotc
,可用于帮助应用程序更快地引导,并极大地减少所需的循环次数。开箱即用它可能会减慢立即启动(因为AOT'd代码是共享库,增加了自己的I/O开销,不支持Serial GC..),但经过精心的调整,我们看到它可以将小型应用程序的启动时间缩短15-30%。
CPU固定:在大型系统上,我们看到的效果源自套接字之间的缓存一致性流量,并且绑定到单个CPU节点可以显著减少启动时间。在Linux上,像这样使用numactl --cpunodebind = 0 $JAVA_HOME/bin/java ...
即可完成。
总的来说,我们已经能够让最小的应用程序在35ms(JDK 9 GA)内执行。各种启动优化已经纳入了JDK10分支,现在我看到的数字仅为28ms。
jaotc
已在 JDK 17 中被移除。替代方案是 GraalVM native-image,尽管它也有一些需要注意的地方。 - Aleksandr Dubinsky使用Java 5或更高版本运行测试。对于Java 5,启动时间已经显著缩短。
除非您可以重用正在运行的VM,否则无法加快速度:预先启动大量VM,然后在每个VM中运行单个测试不会使测试变得更快。
因此,您需要想出一种方法在单个VM中运行多个测试。
如果你真的需要为每个测试启动一个单独的虚拟机,那么你最好使用Sun发布的最新VM版本之一。随着Java版本的更新,启动时间已经大大缩短,在1.6.0_16版本中,“Hello world”程序在我的系统上运行大约需要0.2秒。
如果你的问题更多地是“如何在一个VM中运行更多的测试”,最简单的方法取决于你使用的测试框架(如果你没有使用框架,你应该考虑使用)。使用JUnit和可能是JUnit的ant目标,你可以使用模式匹配要运行的测试,或者将不同的测试类加入到一个测试套件中,然后在一个VM中运行。