AOT Map changes during production run

Ashutosh Mehra asmehra at redhat.com
Fri Oct 10 17:52:16 UTC 2025


@María Arias de Reyna Dominguez <mariasde at redhat.com> can you also please
check and confirm if the patch I posted earlier fixes the issue you were
seeing?

Thanks,
- Ashutosh Mehra


On Thu, Oct 9, 2025 at 3:25 PM Ashutosh Mehra <asmehra at redhat.com> wrote:

> I am able to reproduce the problem Maria is seeing.
> Digging deeper it looks like when the map is generated during the
> production run, the VM skips classes loaded by the custom loaders.
> VM gets the list of classes using
> SystemDictionaryShared::get_all_archived_classes
> <https://github.com/openjdk/jdk/blob/1992b69a4794d1f2f65eaeb6dbb1e1e23a948b6e/src/hotspot/share/classfile/systemDictionaryShared.cpp#L1419-L1423>
> which only iterates through the classes loaded by built-in loaders.
> With the following patch, I am able to get all the classes in the map file
> generated in the prod run:
>
> diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp
> b/src/hotspot/share/classfile/systemDictionaryShared.cpp
> index b092e71f4e7..7e71dbefbfb 100644
> --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
> +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
> @@ -1420,6 +1420,9 @@ void
> SystemDictionaryShared::get_all_archived_classes(bool is_static_archive, Gr
>    get_archive(is_static_archive)->_builtin_dictionary.iterate([&] (const
> RunTimeClassInfo* record) {
>        classes->append(record->klass());
>      });
> +  get_archive(is_static_archive)->_unregistered_dictionary.iterate([&]
> (const RunTimeClassInfo* record) {
> +    classes->append(record->klass());
> +  });
>  }
>
>  class SharedDictionaryPrinter : StackObj {
>
> @Ioi Lam <ioi.lam at oracle.com> Do you think we should do this?
>
> Thanks,
> - Ashutosh Mehra
>
>
> On Thu, Oct 9, 2025 at 1:05 PM María Arias de Reyna Dominguez <
> mariasde at redhat.com> wrote:
>
>> Hi!
>>
>> I am using Infinispan to test this. So I edit their bin/server.conf file
>> to add my own java arguments. Nothing magical beyond that.
>>
>> Depending on if the cache file already exists, I create or not the cache.
>> And then I (used to) always generate the aot.map file:
>>
>> if [ -f "/home/delawen/infinispan-server-15.2.5.Final/aot.map" ]; then
>>   JAVA_OPTS="$JAVA_OPTS -XX:AOTCache=app.aot"
>> else
>>   JAVA_OPTS="$JAVA_OPTS -XX:AOTCacheOutput=app.aot"
>> fi
>> JAVA_OPTS="$JAVA_OPTS -Xlog:aot+map=trace:file=aot.map:none:filesize=0"
>>
>> According to https://bugs.openjdk.org/browse/JDK-8362566 that should
>> re-create the aot.map file based on the current aot cache file.
>>
>> This was a side effect of something else I was testing, but I can try to
>> find a simpler test case if you can't reproduce it in your own testing apps.
>>
>> On Thu, Oct 9, 2025 at 5:24 PM Vladimir Kozlov <
>> vladimir.kozlov at oracle.com> wrote:
>>
>>> On 10/9/25 8:16 AM, Vladimir Kozlov wrote:
>>> > Hi María,
>>> >
>>> > Please provide command lines you use in your experiments.
>>> >
>>> >  >         And then I did a production run using the generated cache,
>>> which
>>> >  >         replaced the `aot.map` with a new one that is much smaller:
>>> >
>>> > We don't support incremental update of AOT cache file. What do you
>>> mean
>>> > by "replaced the `aot.map`" ?
>>>
>>> Sorry, I confused aot.map with aot.cache.
>>>
>>> I assume aot.map is log file produced from AOT cache logs output.
>>>
>>> Still it would be interesting to see your commands.
>>>
>>> Vladimir K
>>>
>>> >
>>> > Thanks,
>>> > Vladimir K
>>> >
>>> > On 10/9/25 12:25 AM, María Arias de Reyna Dominguez wrote:
>>> >> Hi Ashutosh,
>>> >>
>>> >> Training run:
>>> >> $ grep '@@ Class ' aot.map | wc -l
>>> >> 10884
>>> >>
>>> >> Production run:
>>> >> $ grep '@@ Class ' aot.map | wc -l
>>> >> 3431
>>> >>
>>> >> And the sizes of the map file are different:
>>> >> $ du -sh aot.map*
>>> >> 331M aot.map
>>> >> 391M aot.map.0
>>> >> 394M aot.map.1
>>> >>
>>> >> The aot.map is the production run. The file aot.map.1 is the training
>>> >> run.
>>> >>
>>> >> The aot.map.0 is for app.aot.config (app.aot is how I call my aot
>>> cache):
>>> >> $ cat aot.map.0 | head
>>> >> AOT cache map for app.aot.config
>>> >> [header             0x0000000000000000 - 0x00000000000003d8       984
>>> >> bytes]
>>> >> $ grep '@@ Class ' aot.map.0 | wc -l
>>> >> 10606
>>> >>
>>> >> I'm using a locally build version of Java, that's true:
>>> >> $ java --version
>>> >> openjdk 26-internal 2026-03-17
>>> >> OpenJDK Runtime Environment (build 26-internal-adhoc.delawen.jdk)
>>> >> OpenJDK 64-Bit Server VM (build 26-internal-adhoc.delawen.jdk, mixed
>>> >> mode, sharing)
>>> >>
>>> >> Build from:
>>> >> $ git log | head
>>> >> commit 4b4d0cd35a32448e4b056109c502af2765766432
>>> >> Author: Johny Jose <johny.jose at oracle.com <mailto:
>>> johny.jose at oracle.com>>
>>> >> Date:   Tue Oct 7 13:13:42 2025 +0000
>>> >>
>>> >>      8365398: TEST_BUG: java/rmi/transport/checkLeaseInfoLeak/
>>> >> CheckLeaseLeak.java failing intermittently
>>> >>
>>> >>      Reviewed-by: msheppar, smarks, jpai
>>> >>
>>> >> I'm confused :)
>>> >>
>>> >> On Wed, Oct 8, 2025 at 6:31 PM Ashutosh Mehra <asmehra at redhat.com
>>> >> <mailto:asmehra at redhat.com>> wrote:
>>> >>
>>> >>     Hi Maria,
>>> >>     This is strange. I tried the same using the JavacBench app and
>>> >>     didn't see this discrepancy in the map file generated by the
>>> >>     assembly phase and the production run.
>>> >>     You may have already checked it but just to confirm if run "grep
>>> '@@
>>> >>     Class ' t.log | wc -l" on the map file, do you see the same
>>> >> difference?
>>> >>
>>> >>     Thanks,
>>> >>     - Ashutosh Mehra
>>> >>
>>> >>
>>> >>     On Wed, Oct 8, 2025 at 4:36 AM María Arias de Reyna Dominguez
>>> >>     <mariasde at redhat.com <mailto:mariasde at redhat.com>> wrote:
>>> >>
>>> >>         Hi!
>>> >>
>>> >>         I have a question.  I did a training run and generated what
>>> >>         looks like a valid cache.
>>> >>
>>> >>         Summary of the number of elements (for certain types of
>>> >>         elements) the map contains:
>>> >>         ```
>>> >>         Classes in AOT Cache: 10.885
>>> >>         Methods in AOT Cache: 121.393
>>> >>            -> ConstMethods: 121.293
>>> >>            -> MethodCounters: 6.530
>>> >>            -> MethodData: 4.127
>>> >>         ConstantPool: 10.197
>>> >>            -> ConstantPoolCache: 10.197
>>> >>         ```
>>> >>
>>> >>         And then I did a production run using the generated cache,
>>> which
>>> >>         replaced the `aot.map` with a new one that is much smaller:
>>> >>
>>> >>         ```
>>> >>         Classes in AOT Cache: 3.431
>>> >>         Methods in AOT Cache: 38.359
>>> >>            -> ConstMethods: 38.359
>>> >>            -> MethodCounters: 0
>>> >>            -> MethodData: 0
>>> >>         ConstantPool: 3.067
>>> >>            -> ConstantPoolCache: 3.067
>>> >>         ```
>>> >>
>>> >>         As you can see, there are a lot of missing elements!
>>> >>
>>> >>         If I check the md5sum of the actual cache file before and
>>> after
>>> >>         the production run, it stays the same. It is the AOT Cache Map
>>> >>         which changes. Is that... supposed to happen?
>>> >>
>>> >>         Maybe it is a bug related to https://bugs.openjdk.org/browse/
>>> >>         JDK-8362566 <https://bugs.openjdk.org/browse/JDK-8362566> ?
>>> >>
>>> >>         Both map files start with `AOT cache map for app.aot`, it is
>>> not
>>> >>         the map file for the `app.aot.config` that appears during the
>>> >>         training run.
>>> >>
>>> >>         Both the training and the run were the same: just spin up an
>>> >>         Infinispan server and shut it down after a few seconds. But I
>>> >>         guess that's irrelevant because the aot cache file is exactly
>>> >>         the same.
>>> >>
>>> >>         I could stop generating the aot map file on the production run
>>> >>         because there is no need for it, but I forgot to remove it...
>>> >>         and then this happened.
>>> >>
>>> >>         Kind regards,
>>> >>         María Arias de Reyna Domínguez
>>> >>         Senior Software Engineer
>>> >>         She / Her / Hers
>>> >>         ariasdereyna at redhat.com <mailto:ariasdereyna at redhat.com>
>>> >>
>>> >
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20251010/0d675a47/attachment.htm>


More information about the leyden-dev mailing list