error writing the shared archive file with large number of loaded classes

Olivier Bourgain olivierbourgain02 at gmail.com
Wed Apr 16 08:56:56 UTC 2025


Hello,

I have been experimenting with Leyden for a pretty large Spring Boot
application (>1M loc, fat jar is about 240MB) and I think I hit a
limitation of the current implementation of  Leyden.

I got the following error message at the end of the training run:

[31,832s][error  ][cds,heap   ] [ 0] {0x000000060080be70}
jdk.internal.loader.ArchivedClassLoaders::appLoader (offset = 16)

[31,832s][error  ][cds,heap   ] [ 1] {0x0000000601400000}
jdk.internal.loader.ClassLoaders$AppClassLoader::parallelLockMap (offset =
36)

[31,832s][error  ][cds,heap   ] [ 2] {0x000000060095c5a8}
java.util.concurrent.ConcurrentHashMap

[31,832s][error  ][cds,heap   ] Cannot archive the sub-graph referenced
from [Ljava.util.concurrent.ConcurrentHashMap$Node; object
(0x000000060354bc88) size 262160, skipped.

[31,832s][error  ][cds    ] An error has occurred while writing the shared
archive file.

So it looks like some classloader has a very large ConcurrentHashMap that
ends up with a backing array of length 65536.

Tracing back to Leyden’s sources, I found that the the archived objects
size is limited

   -


   https://github.com/openjdk/leyden/blob/master/src/hotspot/share/cds/heapShared.cpp#L295
   -


   https://github.com/openjdk/leyden/blob/master/src/hotspot/share/cds/archiveHeapWriter.cpp#L118
   <https://github.com/openjdk/leyden/blob/master/src/hotspot/share/cds/archiveHeapWriter.cpp#L121>
   -


   https://github.com/openjdk/leyden/blob/83c7d3bbe860656ee403fa29df6a9e0aae962839/src/hotspot/share/cds/archiveHeapWriter.hpp#L118



By adding a --add-opens java.base/java.util=ALL-UNNAMED to the command
line, it disables the optimized module handling

[0.001s][info][cds] optimized module handling: disabled due to incompatible
property: jdk.module.addopens=java.base/java.util=ALL-UNNAMED

And the error goes away.

I tried to make my case work without adding some add-opens that are not
required by the app. As the limit in object size comes from
MIN_GC_REGION_ALIGNMENT, which is limited by Shenandoah’s region size, and
I don’t use that GC, I simply modified is_too_large_to_archive() to always
return false. Then the archiving with optimized module handling succeeds.

I created a Github repo to reproduce the issue, see the readme there:
https://github.com/obourgain/leyden-classloader

With regard to the improvements in startup time (on a M1 mac), here is what
is get:

   -

   base line, exploded Spring Boot jar = 11s
   -

   spring AOT = 10.5s
   -

   leyden with optimized module handling disabled = 7.8s
   -

   leyden with optimized module handling enabled = 7.1s
   -

   leyden with optimized module handling disabled and Spring AOT = 7.3s
   -

   leyden with optimized module handling enabled and Spring AOT = 6.3s


Overall, I think that’s pretty impressive improvements for this app’s
startup which was pretty efficient already. Moreover, I did that on a
project that started 12 or 13 years ago, so it shows that Leyden is
applicable for that kind of project with substantial gains.

I plan to try the premain branch soon.

Let me know if I can help with more information.

(this message was first submitted before I subscribed to the list. A copy
of it may be pending review by the admin. Feel free to delete the pending
copy)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/leyden-dev/attachments/20250416/f5c3023e/attachment.htm>


More information about the leyden-dev mailing list