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