简体   繁体   English

如何加快 Java VM (JVM) 启动时间?

[英]How to speed up Java VM (JVM) startup time?

I am running tests that start multiple JVM processes.我正在运行启动多个 JVM 进程的测试。 Summary startup time of JVMs is quite significant compared to time of actual tests that run inside JVM.与在 JVM 内部运行的实际测试的时间相比,JVM 的摘要启动时间非常重要。 How do I speed things up?我如何加快速度?

I have used "-client" option already, this does help but not as much as I wanted.我已经使用了“-client”选项,这确实有帮助,但没有我想要的那么多。 Is there any other way, say preloading bunch of JVMs and reusing them somehow?有没有其他方法,比如预加载一堆 JVM 并以某种方式重用它们?

If you do want to reuse JVMs, the "somehow" could be Nailgun .如果您确实想重用 JVM,“不知何故”可能是Nailgun Nailgun keeps a JVM running, then uses a light native client to start a particular class and handle console io. Nailgun 保持 JVM 运行,然后使用轻量级本地客户端启动特定类并处理控制台 io。 This is good for running small command line Java utilities, but as it reuses the same JVM can accumulate state.这对于运行小型命令行 Java 实用程序很有用,但由于它重用相同的 JVM 可能会累积状态。

To work around the state accumulation, at the cost of running multiple JVMs, another option is Drip .为了解决状态累积,以运行多个 JVM 为代价,另一种选择是Drip Drip keeps a fresh JVM spun up in reserve with the correct classpath and other JVM options so you can quickly connect and use it when needed, then throw it away. Drip 使用正确的类路径和其他 JVM 选项保留一个新的 JVM,以便您可以在需要时快速连接和使用它,然后将其丢弃。 Drip hashes the JVM options and stores information about how to connect to the JVM in a directory with the hash value as its name. Drip 对 JVM 选项进行哈希处理,并将有关如何连接到 JVM 的信息存储在以哈希值作为其名称的目录中。

JVM startup performance can be improved in many ways: CDS, straight up tuning, CPU pinning and jlink (since JDK 9) can be good options. JVM 启动性能可以通过多种方式提高:CDS、直接调优、CPU 固定和 jlink(自 JDK 9)都是不错的选择。 AOT (JDK 9, Linux-only) has some rough edges but can be tuned to help small applications. AOT(JDK 9,仅限 Linux)有一些粗糙的地方,但可以调整以帮助小型应用程序。

CDS CDS

Class Data Sharing was developed for the client VM back in 1.5, but has been much improved since to work on all variants of HotSpot (all GCs since 8), bringing a substantial boost to startup performance when enabled.类数据共享是在 1.5 中为客户端 VM 开发的,但自从在 HotSpot 的所有变体(自 8 以来的所有 GC)上工作以来得到了很大改进,启用后大大提高了启动性能。

CDS is always enabled on 32-bit JRE client installs, but might need some manual steps to be enabled elsewhere: CDS 始终在 32 位 JRE 客户端安装上启用,但可能需要在其他地方启用一些手动步骤:

  1. Run java -Xshare:dump to generate a CDS shared archive运行java -Xshare:dump生成 CDS 共享存档
  2. Add -Xshare:auto to your command to ensure it's used-Xshare:auto添加到您的命令中以确保它被使用

Other tuning其他调音

While -client may or may not actually do anything (the JVM on many systems doesn't ship with a client VM - none since 9, actually), there are numerous ways to tune a HotSpot server JVM to behave more like a client VM:虽然-client实际上可能会也可能不会做任何事情(许多系统上的 JVM 不附带客户端 VM - 实际上从 9 开始就没有),有很多方法可以调整 HotSpot 服务器 JVM 以使其更像客户端 VM:

  • Use only the C1 (client) compiler: -XX:TieredStopAtLevel=1仅使用 C1(客户端)编译器: -XX:TieredStopAtLevel=1
  • Use as few compiler threads as possible: -XX:CICompilerCount=1使用尽可能少的编译器线程: -XX:CICompilerCount=1
  • Use the single-threaded serial GC: -XX:+UseSerialGC使用单线程串行GC: -XX:+UseSerialGC
  • Limit heap usage (especially on large systems), eg, -Xmx512m限制堆使用(尤其是在大型系统上),例如-Xmx512m

This should be enough to boost startup for a small short-running application, but may have very negative effects on peak performance.这应该足以提高小型短期运行应用程序的启动速度,但可能会对峰值性能产生非常负面的影响。 You can of course get even further by disabling features you might not be using, such as -XX:-UsePerfData (disables some runtime information retrievable using MXBeans and jvmstat).当然,您可以通过禁用您可能不使用的功能来获得更多功能,例如-XX:-UsePerfData (禁用一些可使用 MXBeans 和 jvmstat 检索的运行时信息)。

Advanced先进的

  • jlink is a new tool available in Java 9 which allows you to build custom runtime images. jlink是 Java 9 中提供的一个新工具,它允许您构建自定义运行时映像。 If your console application only uses a small subset of JDK modules, a custom runtime can be made very small, which can improve startup times further.如果您的控制台应用程序仅使用一小部分 JDK 模块,则可以将自定义运行时做得非常小,这可以进一步缩短启动时间。 A minimal image including only the java.base module, and might boost startup times by ~10-20ms depending on hardware and other tuning: $JAVA_HOME/bin/jlink --add-modules java.base --module-path $JAVA_HOME/jmods --output jbase一个仅包含 java.base 模块的最小映像,并且可能会根据硬件和其他调整将启动时间提高约 10-20 毫秒: $JAVA_HOME/bin/jlink --add-modules java.base --module-path $JAVA_HOME/jmods --output jbase

  • (Linux only) Java 9 introduces an experimental AOT compiler , jaotc , which can be used to help applications boot faster and spend a lot less cycles doing so. (仅限 Linux)Java 9 引入了一个实验性的AOT 编译器jaotc ,它可用于帮助应用程序更快地启动并花费更少的周期。 Out-of-the-box it might slow down immediate startup (since the AOT'd code is a shared library which adds its own I/O overheads, doesn't support the Serial GC..), but with careful tuning we've seen it reduce start-up times of small applications by 15-30%.开箱即用的它可能会减慢立即启动的速度(因为 AOT 代码是一个共享库,它增加了自己的 I/O 开销,不支持串行 GC..),但是通过仔细调整我们我们已经看到它将小型应用程序的启动时间减少了 15-30%。

  • CPU pinning: on large systems, we've seen effects that stem from cache coherence traffic between sockets, and binding to a single CPU node can cut startup times considerably. CPU 固定:在大型系统上,我们已经看到了来自套接字之间缓存一致性流量的影响,并且绑定到单个 CPU 节点可以大大缩短启动时间。 On Linux something like numactl --cpunodebind=0 $JAVA_HOME/bin/java ... should do the trick.在 Linux 上, numactl --cpunodebind=0 $JAVA_HOME/bin/java ...应该可以解决问题。

All in all we've been able to get minimal applications to execute in as little as 35ms (JDK 9 GA).总而言之,我们已经能够让最少的应用程序在 35 毫秒内执行(JDK 9 GA)。 Various startup optimizations has gone into the JDK10 branch and I'm now seeing numbers as low as 28ms.各种启动优化已经进入 JDK10 分支,我现在看到的数字低至 28 毫秒。

Why not load all the tests in one JVM ?为什么不在一个 JVM 中加载所有测试? Can you do one or more of the following ?您可以执行以下一项或多项操作吗?

  1. load all the tests via a higher-level class ?通过更高级别的类加载所有测试?
  2. specify the test classes in a list (config file) and load each in sequence via Class.forName() ?在列表(配置文件)中指定测试类并通过Class.forName()按顺序加载每个类?
  3. if isolation is important, you can create a different class loader per test如果隔离很重要,您可以为每个测试创建一个不同的类加载器

If memory allocation is sizeable, it may speed things up by specifying the JVM memory startup size to the same figure as the maximum allocatable memory ( -Xms vs -Xmx ), which will save the JVM having to go back to the OS for more memory.如果内存分配很大,它可以通过将 JVM 内存启动大小指定为与最大可分配内存( -Xms-Xmx )相同的数字来加快速度,这将使 JVM 不必返回操作系统以获得更多内存. However in this scenario I think that's unlikely to be the problem.但是,在这种情况下,我认为这不太可能是问题所在。

To add to what has been said by others, next version of Java ( Java 7 Java 8 Java 9) should add a new improvement in JVM start-up times, due to modularization of the platform, according to this link .根据此链接,为了补充其他人所说的内容,由于平台的模块化,下一版本的 Java( Java 7 Java 8 Java 9)应该对 JVM 启动时间进行新的改进。

Quote:引用:

One benefit of modularization is that the platform is a smaller download, potentially improving start-up performance.模块化的一个好处是平台的下载量较小,可能会提高启动性能。 Having a smaller memory footprint also enables significant performance improvements, especially for desktop applications.更小的内存占用还可以显着提高性能,尤其是对于桌面应用程序。

Run the tests with Java 5 or better.使用 Java 5 或更高版本运行测试。 Startup time has been reduced significantly for Java 5. Java 5 的启动时间显着减少。

You can't get much faster unless you can reuse a running VM: Prestarting a lot of them and then running a single test in each won't make your tests any faster.除非您可以重用正在运行的虚拟机,否则您无法获得更快的速度:预先启动大量虚拟机,然后在每个虚拟机中运行单个测试不会使您的测试更快。

So you need to figure a way to run several tests in a single VM.因此,您需要想办法在单个 VM 中运行多个测试。

If it's really necessary for you to start a separate VM for each test, your best option is probably to make sure that you use one of the newest VM releases from Sun.如果确实有必要为每个测试启动一个单独的 VM,那么最好的选择可能是确保使用 Sun 的最新 VM 版本之一。 The startup time has decreased quite a bit over the last Java versions and with 1.6.0_16, a simple "Hello world" program takes about 0.2s to run on my system.与上一个 Java 版本相比,启动时间减少了很多,在 1.6.0_16 中,一个简单的“Hello world”程序在我的系统上运行大约需要 0.2 秒。

If your question rather was ment to be "how to run more tests in one VM", the easiest approach depends on which test framework you are using (if you're not using a framework, you should really consider so).如果您的问题是“如何在一个 VM 中运行更多测试”,那么最简单的方法取决于您使用的测试框架(如果您不使用框架,则应该真正考虑)。 With JUnit and possibly the ant target for JUnit, you can either use patterns to match the tests you want to run or alternatively join different test classes in a test suite, which can then be run in one VM.使用 JUnit 以及可能是 JUnit 的 ant 目标,您可以使用模式来匹配要运行的测试,或者将不同的测试类加入一个测试套件中,然后可以在一个 VM 中运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM