|
| 1 | +[[aot-cache]] |
| 2 | += JVM AOT Cache |
| 3 | +:page-aliases: integration/class-data-sharing.adoc |
| 4 | +:page-aliases: integration/cds.adoc |
| 5 | + |
| 6 | +The ahead-of-time cache is a JVM feature introduced in Java 24 via the |
| 7 | +https://openjdk.org/jeps/483[JEP 483] that can help reduce the startup time and memory |
| 8 | +footprint of Java applications. AOT cache is a natural evolution of https://docs.oracle.com/en/java/javase/17/vm/class-data-sharing.html[Class Data Sharing (CDS)]. |
| 9 | +Spring Framework supports both CDS and AOT cache, and it is recommended that you use the |
| 10 | +later if available in the JVM version your are using (Java 24+). |
| 11 | + |
| 12 | +To use this feature, an AOT cache should be created for the particular classpath of the |
| 13 | +application. It is possible to create this cache on the deployed instance, or during a |
| 14 | +training run performed for example when packaging the application thanks to an hook-point |
| 15 | +provided by the Spring Framework to ease such use case. Once the cache is available, users |
| 16 | +should opt in to use it via a JVM flag. |
| 17 | + |
| 18 | +NOTE: If you are using Spring Boot, it is highly recommended to leverage its |
| 19 | +{spring-boot-docs-ref}/packaging/efficient.html#packaging.efficient.unpacking[executable JAR unpacking support] |
| 20 | +which is designed to fulfill the class loading requirements of both AOT cache and CDS. |
| 21 | + |
| 22 | +== Creating the cache |
| 23 | + |
| 24 | +An AOT cache can typically be created when the application exits. The Spring Framework |
| 25 | +provides a mode of operation where the process can exit automatically once the |
| 26 | +`ApplicationContext` has refreshed. In this mode, all non-lazy initialized singletons |
| 27 | +have been instantiated, and `InitializingBean#afterPropertiesSet` callbacks have been |
| 28 | +invoked; but the lifecycle has not started, and the `ContextRefreshedEvent` has not yet |
| 29 | +been published. |
| 30 | + |
| 31 | +To create the cache during the training run, it is possible to specify the `-Dspring.context.exit=onRefresh` |
| 32 | +JVM flag to start then exit your Spring application once the |
| 33 | +`ApplicationContext` has refreshed: |
| 34 | + |
| 35 | + |
| 36 | +-- |
| 37 | +[tabs] |
| 38 | +====== |
| 39 | +AOT cache:: |
| 40 | ++ |
| 41 | +[source,bash,subs="verbatim,quotes"] |
| 42 | +---- |
| 43 | +# Both commands need to be run with the same classpath |
| 44 | +java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -Dspring.context.exit=onRefresh ... |
| 45 | +java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot ... |
| 46 | +---- |
| 47 | +
|
| 48 | +CDS:: |
| 49 | ++ |
| 50 | +[source,bash,subs="verbatim,quotes"] |
| 51 | +---- |
| 52 | +# To create a CDS archive, your JDK/JRE must have a base image |
| 53 | +java -XX:ArchiveClassesAtExit=app.jsa -Dspring.context.exit=onRefresh ... |
| 54 | +---- |
| 55 | +====== |
| 56 | +-- |
| 57 | + |
| 58 | +== Using the cache |
| 59 | + |
| 60 | +Once the cache file has been created, you can use it to start your application faster: |
| 61 | + |
| 62 | +-- |
| 63 | +[tabs] |
| 64 | +====== |
| 65 | +AOT cache:: |
| 66 | ++ |
| 67 | +[source,bash,subs="verbatim"] |
| 68 | +---- |
| 69 | +# With the same classpath (or a superset) tan the training run |
| 70 | +java -XX:AOTCache=app.aot ... |
| 71 | +---- |
| 72 | +
|
| 73 | +CDS:: |
| 74 | ++ |
| 75 | +[source,bash,subs="verbatim"] |
| 76 | +---- |
| 77 | +# With the same classpath (or a superset) tan the training run |
| 78 | +java -XX:SharedArchiveFile=app.jsa ... |
| 79 | +---- |
| 80 | +====== |
| 81 | +-- |
| 82 | + |
| 83 | +Pay attention to the logs and the startup time to check if the AOT cache is used successfully. |
| 84 | +To figure out how effective the cache is, you can enable class loading logs by adding |
| 85 | +an extra attribute: `-Xlog:class+load:file=aot-cache.log`. This creates a `aot-cache.log` with |
| 86 | +every attempt to load a class and its source. Classes that are loaded from the cache should have |
| 87 | +a "shared objects file" source, as shown in the following example: |
| 88 | + |
| 89 | +[source,shell,subs="verbatim"] |
| 90 | +---- |
| 91 | +[0.151s][info][class,load] org.springframework.core.env.EnvironmentCapable source: shared objects file |
| 92 | +[0.151s][info][class,load] org.springframework.beans.factory.BeanFactory source: shared objects file |
| 93 | +[0.151s][info][class,load] org.springframework.beans.factory.ListableBeanFactory source: shared objects file |
| 94 | +[0.151s][info][class,load] org.springframework.beans.factory.HierarchicalBeanFactory source: shared objects file |
| 95 | +[0.151s][info][class,load] org.springframework.context.MessageSource source: shared objects file |
| 96 | +---- |
| 97 | + |
| 98 | +If the AOT cache can't be enabled or if you have a large number of classes that are not loaded from |
| 99 | +the cache, make sure that the following conditions are fulfilled when creating and using the cache: |
| 100 | + |
| 101 | + - The very same JVM must be used. |
| 102 | + - The classpath must be specified as a JAR or a list of JARs, and avoid the usage of directories and `*` wildcard characters. |
| 103 | + - The timestamps of the JARs must be preserved. |
| 104 | + - When using the cache, the classpath must be the same than the one used to create it, in the same order. |
| 105 | +Additional JARs or directories can be specified *at the end* (but won't be cached). |
0 commit comments