How to speed up Java VM (JVM) startup time?
Asked Answered
W

6

45

I am running tests that start multiple JVM processes. Summary startup time of JVMs is quite significant compared to time of actual tests that run inside JVM. How do I speed things up?

I have used "-client" option already, this does help but not as much as I wanted. Is there any other way, say preloading bunch of JVMs and reusing them somehow?

Worrywart answered 29/9, 2009 at 8:43 Comment(0)
O
38

If you do want to reuse JVMs, the "somehow" could be Nailgun. Nailgun keeps a JVM running, then uses a light native client to start a particular class and handle console io. This is good for running small command line Java utilities, but as it reuses the same JVM can accumulate state.

To work around the state accumulation, at the cost of running multiple JVMs, another option is 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 hashes the JVM options and stores information about how to connect to the JVM in a directory with the hash value as its name.

Onstad answered 29/9, 2009 at 13:29 Comment(2)
Nailgun is indeed uber-awesome.Homozygous
@Pete Nailgun is amazing but it is not secure!Elodiaelodie
J
18

JVM startup performance can be improved in many ways: CDS, straight up tuning, CPU pinning and jlink (since JDK 9) can be good options. AOT (JDK 9, Linux-only) has some rough edges but can be tuned to help small applications.

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.

CDS is always enabled on 32-bit JRE client installs, but might need some manual steps to be enabled elsewhere:

  1. Run java -Xshare:dump to generate a CDS shared archive
  2. Add -Xshare:auto to your command to ensure it's used

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:

  • Use only the C1 (client) compiler: -XX:TieredStopAtLevel=1
  • Use as few compiler threads as possible: -XX:CICompilerCount=1
  • Use the single-threaded serial GC: -XX:+UseSerialGC
  • Limit heap usage (especially on large systems), e.g., -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).

Advanced

  • jlink is a new tool available in Java 9 which allows you to build custom runtime images. 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. 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

  • (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. 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%.

  • 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. On Linux something like numactl --cpunodebind=0 $JAVA_HOME/bin/java ... should do the trick.

All in all we've been able to get minimal applications to execute in as little as 35ms (JDK 9 GA). Various startup optimizations has gone into the JDK10 branch and I'm now seeing numbers as low as 28ms.

Joli answered 1/10, 2017 at 20:17 Comment(1)
jaotc has been removed in JDK 17. The alternative is GraalVM native-image, although it has its share of gotchas.Dictograph
C
2

Why not load all the tests in one 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() ?
  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. However in this scenario I think that's unlikely to be the problem.

Ceres answered 29/9, 2009 at 8:48 Comment(0)
J
2

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.

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.

Jornada answered 29/9, 2009 at 9:18 Comment(4)
Apparently this has ben deferred until JDK 8. (source: openjdk.java.net/projects/jdk7/features)Jaynes
I really wish project Coin or whatever they use to modularize the core libraries wasn't always getting pushed back. I'd love to see core library code reduction by dropping Enumeration and other early false starts.Bowden
After "some" time it is finally coming to Java 9 :DEirene
openj9 should have a similar feature.Culver
A
1

Run the tests with Java 5 or better. Startup time has been reduced significantly for 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.

Armored answered 29/9, 2009 at 9:6 Comment(0)
A
0

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. 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.

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). 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.

Acanthaceous answered 29/9, 2009 at 9:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.