Using AOTCaching with debug (JDWP)
Charles Oliver Nutter
headius at headius.com
Tue Jan 27 17:15:43 UTC 2026
FWIW I run into this with JRuby, because we have designed our app launcher
to always enable as much CDS and AOT stuff as is appropriate for the host
JVM. I'm not as concerned about AOT being disable during debugging, but the
following error is pretty annoying when auto-dumping a CDS cache:
```
[] jruby $ jruby --rmcache
[] jruby $ jruby -J$JAVADEBUG -e 1
Error occurred during CDS dumping
CDS dumping does not support native JVMTI agent, name: jdwp
[] jruby $ jruby -e 1
[] jruby $ jruby -J$JAVADEBUG -e 1
Listening for transport dt_socket at address: 5005
```
Debugging works fine as long as I've already done a "clean" run that
succesfully dumped my CDS archive.
The relevant Java command line for the failed call above is as follows:
```
java @/Users/headius/work/jruby/bin/.jruby.java_opts ...
-XX:+AutoCreateSharedArchive
-XX:SharedArchiveFile=/Users/headius/work/jruby/lib/jruby-java25+36-LTS.jsa
-Xlog:cds=off -Xlog:cds+dynamic=off ...
In this case I'm running JDK 25, but we have not fully utilized AOT
features there yet.
I'd prefer (and I think most folks would prefer) simply getting a warning
that CDS dumping has been disabled, rather than a hard error that
terminates execution.
On Tue, Jan 27, 2026 at 8:35 AM Anthony Dahanne <anthony.dahanne at gmail.com>
wrote:
> Hello Ioi,
> Thanks for your answer; I now understand why the gating of JVMTI when
> AOTClassLinking is enabled.
>
> After reading your answer, and reading https://openjdk.org/jeps/483 , can
> I sum up the situation by saying:
>
> -XX:+AOTClassLinking (>=Java 25)
> * enabled by default when you're training using -XX:AOTMode=create
> * ahead-of-time loading and linking enhances startup time even more than
> CDS (cf your benchmark in JEP 483 with HelloStream and Spring PetClinic)
> * can not be applied with JVMTI (Java debug), customized
> java.security.manager
>
> -XX:-AOTClassLinking (>=Java 25)
> * reverts back to "plain" CDS cache
>
> Thanks again!
>
>
> Le mar. 27 janv. 2026, à 02 h 27, <ioi.lam at oracle.com> a écrit :
>
>> When JDWP is used, AOT is disabled by this check:
>>
>>
>> https://github.com/openjdk/jdk/blob/cba7d88ca427984ebb27a1634aab10a62c9eede1/src/hotspot/share/cds/filemap.cpp#L1743-L1748
>>
>> The reason we have this check is that when -XX:+AOTClassLinking is
>> enabled (by default in AOT cache creation), some class initializers are
>> executed in the AOT assembly phase, and are not executed in the
>> production run.
>>
>> As a result, some breakpoints will not work.
>>
>> Here's an example. I have rebuilt the JVM to disable the above check:
>>
>>
>>
>> ===============================================================================
>>
>> Without AOT cache: you can break at java.lang.invoke.Invokers.<clinit>
>>
>>
>> ===============================================================================
>> $ jdb -launch -classpath HelloWorld.jar -R-XX:AOTMode=off
>> -R-XX:AOTCache=hw.aot java.lang.invoke.Invokers
>> Set uncaught java.lang.Throwable
>> Set deferred uncaught java.lang.Throwable
>> Initializing jdb ...
>> >
>> VM Started: No frames on the current call stack
>>
>> main[1] stop in java.lang.invoke.Invokers.<clinit>
>> Deferring breakpoint java.lang.invoke.Invokers.<clinit>.
>> It will be set after the class is loaded.
>> main[1] cont
>> > Set deferred breakpoint java.lang.invoke.Invokers.<clinit>
>>
>> Breakpoint hit: "thread=main", java.lang.invoke.Invokers.<clinit>(),
>> line=47 bci=0
>>
>> main[1] where
>> [1] java.lang.invoke.Invokers.<clinit> (Invokers.java:47)
>> [2] java.lang.invoke.MethodHandleNatives.linkCallSiteImpl
>> (MethodHandleNatives.java:263)
>> [3] java.lang.invoke.MethodHandleNatives.linkCallSite
>> (MethodHandleNatives.java:240)
>> [4] java.util.ResourceBundle$Control.<clinit>
>> (ResourceBundle.java:2,833)
>> [5] java.util.ResourceBundle.getDefaultControl
>> (ResourceBundle.java:1,508)
>> [6] java.util.ResourceBundle.getDefaultControl
>> (ResourceBundle.java:1,503)
>> [7] java.util.ResourceBundle.getBundle (ResourceBundle.java:863)
>> [8] sun.launcher.LauncherHelper$ResourceBundleHolder.<clinit>
>> (LauncherHelper.java:124)
>> [9] sun.launcher.LauncherHelper.getLocalizedMessage
>> (LauncherHelper.java:532)
>> [10] sun.launcher.LauncherHelper.abort (LauncherHelper.java:720)
>> [11] sun.launcher.LauncherHelper.validateMainMethod
>> (LauncherHelper.java:944)
>> [12] sun.launcher.LauncherHelper.checkAndLoadMain
>> (LauncherHelper.java:778)
>> main[1] cont
>> > Error: Main method not found in class java.lang.invoke.Invokers,
>> please define the main method as:
>> public static void main(String[] args)
>> or a JavaFX application class must extend javafx.application.Application
>>
>> The application exited
>>
>>
>> ===============================================================================
>>
>> With AOT cache: you cannot break at java.lang.invoke.Invokers.<clinit>
>>
>>
>> ===============================================================================
>>
>>
>> $ jdb -launch -classpath HelloWorld.jar -R-XX:AOTMode=on
>> -R-XX:AOTCache=hw.aot java.lang.invoke.Invokers
>> Set uncaught java.lang.Throwable
>> Set deferred uncaught java.lang.Throwable
>> Initializing jdb ...
>> >
>> VM Started: No frames on the current call stack
>>
>> main[1] stop in java.lang.invoke.Invokers.<clinit>
>> Set breakpoint java.lang.invoke.Invokers.<clinit>
>> main[1] cont
>> > Error: Main method not found in class java.lang.invoke.Invokers,
>> please define the main method as:
>> public static void main(String[] args)
>> or a JavaFX application class must extend javafx.application.Application
>>
>> The application exited
>>
>>
>> On 1/26/26 9:39 PM, Anthony Dahanne wrote:
>> > Hello all!
>> > I'm trying to run an AOTCaching optimized app in debug mode;
>> > unfortunately, it does not seem to be supported.
>> >
>> > Using a JDK 25.0.1, during the training run I have:
>> >
>> > ```
>> > [creator] Temporary AOTConfiguration recorded:
>> application.aot.config
>> > [creator] Launching child process
>> > /layers/paketo-buildpacks_bellsoft-liberica/jre/bin/java to assemble
>> > AOT cache application.aot using configuration application.aot.config
>> > [creator] Picked up JAVA_TOOL_OPTIONS:
>> > -Djava.class.path=runner.jar:lib/spring-cloud-bindings-2.0.4.jar
>> > -agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,suspend=n
>> > -XX:+AOTClassLinking -Dspring.context.exit=onRefresh
>> > -XX:AOTCacheOutput=application.aot
>> > -XX:AOTConfiguration=application.aot.config -XX:AOTMode=create
>> > [creator] Reading AOTConfiguration application.aot.config and
>> > writing AOTCache application.aot
>> > [creator] [0.262s][warning][aot] Skipping
>> > io/micrometer/core/instrument/config/InvalidConfigurationException:
>> > Unlinked class not supported by AOTClassLinking
>> > [creator] [0.262s][warning][aot] Skipping
>> > org/springframework/web/servlet/view/freemarker/FreeMarkerView:
>> > Unlinked class not supported by AOTClassLinking
>> > [creator] [0.262s][warning][aot] Skipping
>> > org/springframework/boot/logging/log4j2/Log4J2LoggingSystem: Unlinked
>> > class not supported by AOTClassLinking
>> > [creator] [0.263s][warning][aot] Skipping
>> > org/springframework/core/ReactiveAdapterRegistry$ReactorAdapter:
>> > Unlinked class not supported by AOTClassLinking
>> > [creator] AOTCache creation is complete: application.aot
>> > 56819712 bytes
>> > [creator] Removed temporary AOT configuration file
>> > application.aot.config
>> > ```
>> >
>> > but at runtime, I have:
>> > ```
>> > Picked up JAVA_TOOL_OPTIONS:
>> >
>> -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties
>>
>> > -XX:+ExitOnOutOfMemoryError
>> > -agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,suspend=n
>> > -XX:MaxDirectMemorySize=10M -Xmx14945375K -XX:MaxMetaspaceSize=78944K
>> > -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions
>> > -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics
>> > -XX:AOTCache=application.aot
>> > -Dorg.springframework.cloud.bindings.boot.enable=true
>> > [0.032s][error][aot] AOT cache has aot-linked classes. It cannot be
>> > used with JDWP agent
>> > [0.034s][error][aot] An error has occurred while processing the AOT
>> > cache. Run with -Xlog:aot for details.
>> > [0.034s][error][aot] Unable to map shared spaces
>> > Listening for transport dt_socket at address: 8000
>> > ```
>> >
>> > If I enable `-Xlog:aot` at runtime, I have:
>> >
>> > ```
>> > Picked up JAVA_TOOL_OPTIONS: -Xlog:aot
>> >
>> -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties
>>
>> > -XX:+ExitOnOutOfMemoryError
>> > -agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,suspend=n
>> > -XX:MaxDirectMemorySize=10M -Xmx15196043K -XX:MaxMetaspaceSize=78944K
>> > -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions
>> > -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics
>> > -XX:AOTCache=application.aot
>> > -Dorg.springframework.cloud.bindings.boot.enable=true
>> > [0.033s][info][aot] trying to map application.aot
>> > [0.033s][info][aot] Opened AOT cache application.aot.
>> > [0.033s][info][aot] The AOT cache was created with UseCompressedOops =
>> > 1, UseCompressedClassPointers = 1, UseCompactObjectHeaders = 0
>> > [0.033s][info][aot] Core region alignment: 65536
>> > [0.033s][info][aot] ArchiveRelocationMode: 1
>> > [0.033s][info][aot] ArchiveRelocationMode == 1: always map archive(s)
>> > at an alternative address
>> > [0.033s][info][aot] Try to map archive(s) at an alternative address
>> > [0.033s][info][aot] Reserved archive_space_rs [0x0000003000000000 -
>> > 0x0000003004000000] (67108864) bytes (includes protection zone)
>> > [0.033s][info][aot] Reserved class_space_rs [0x0000003004000000 -
>> > 0x0000003008000000] (67108864) bytes
>> > [0.033s][info][aot] Mapped static region #0 at base
>> > 0x0000003000010000 top 0x0000003001500000 (ReadWrite)
>> > [0.033s][info][aot] Mapped static region #1 at base
>> > 0x0000003001500000 top 0x0000003003200000 (ReadOnly)
>> > [0.033s][info][aot] Mapped static region #2 at base
>> > 0x0000ffff5c120000 top 0x0000ffff5c1e0000 (Bitmap)
>> > [0.069s][info][aot] archived module property jdk.module.main: (null)
>> > [0.069s][info][aot] archived module property jdk.module.addexports:
>> (null)
>> > [0.069s][info][aot] archived module property jdk.module.addmods: (null)
>> > [0.069s][info][aot] archived module property
>> > jdk.module.enable.native.access: (null)
>> > [0.069s][info][aot] archived module property jdk.module.addopens: (null)
>> > [0.069s][info][aot] archived module property jdk.module.addreads: (null)
>> > [0.069s][info][aot] optimized module handling: enabled
>> > [0.069s][info][aot] full module graph: enabled
>> > [0.069s][error][aot] AOT cache has aot-linked classes. It cannot be
>> > used with JDWP agent
>> > [0.069s][info ][aot] Unmapping region #0 at base 0x0000003000010000
>> > (ReadWrite)
>> > [0.069s][info ][aot] Region #0 (ReadWrite) is in a reserved space, it
>> > will be freed when the space is released
>> > [0.069s][info ][aot] Unmapping region #1 at base 0x0000003001500000
>> > (ReadOnly)
>> > [0.069s][info ][aot] Region #1 (ReadOnly) is in a reserved space, it
>> > will be freed when the space is released
>> > [0.069s][info ][aot] Unmapping region #2 at base 0x0000ffff5c120000
>> > (Bitmap)
>> > [0.069s][error][aot] An error has occurred while processing the AOT
>> > cache. Run with -Xlog:aot for details.
>> > [0.069s][error][aot] Unable to map shared spaces
>> > Listening for transport dt_socket at address: 8000
>> > ```
>> >
>> > I have tried several variations using ` -XX:+AOTClassLinking` during
>> > the training run, but that did not change a thing.
>> >
>> > Is it possible to use AOTCaching when debug is enabled?
>> >
>> > Thank you!
>> >
>> >
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20260127/841369e4/attachment.htm>
More information about the leyden-dev
mailing list