JDK-8275509: (jlink) SystemModulesPlugin generates a jdk.internal.module.SystemModules$all.class which isn't reproducible

Jaikiran Pai jai.forums2013 at gmail.com
Fri Oct 22 08:09:45 UTC 2021


Hello Ioi,

On 22/10/21 12:29 pm, Ioi Lam wrote:
>
>
> On 10/21/21 9:09 PM, Jaikiran Pai wrote:
>> Hello Ioi,
>>
>>
>>>
>>> This is my initial analysis of the problem.
>>>
>>> ====>>> Can anyone think of similar problems that may happen elsewhere?
>>>
>>> The static constructors of enum classes are executed at both CDS 
>>> dump time and run time. E.g.,
>>>
>>>     public enum Modifier {
>>>         OPEN
>>>     }
>>>
>>> The <clinit> method essentially does this:
>>>
>>>     public static final Modifier OPEN = new Modifier("OPEN");
>>>
>>> If a reference of Modifier.OPEN is stored inside the CDS archived 
>>> heap during dump time, it will be different than the value of 
>>> Modifier.OPEN that is re-created at runtime by the execution of 
>>> Modifier.<clinit>
>>
>> I have almost next to nothing knowledge about CDS internals. My only 
>> understanding of it is based on some documentation that I have read. 
>> One of them being this one 
>> https://docs.oracle.com/en/java/javase/17/vm/class-data-sharing.html#GUID-7EAA3411-8CF0-4D19-BD05-DF5E1780AA91.
>>
>> Based on that documentation (and other similar ones), it was my 
>> understanding that CDS was meant to store/share class "metadata" like 
>> it states in that doc:
>>
>> "When the JVM starts, the shared archive is memory-mapped to allow 
>> sharing of read-only JVM metadata for these classes among multiple 
>> JVM processes."
>>
>> But from what you explain in that enum example, it looks like it also 
>> stores class instance data that is computed at build time on the host 
>> where the JDK image was generated? Did I understand it correctly? Is 
>> this only for enums or does it also store the static initialization 
>> data of "class" types too? If it does store the static init data of 
>> class types too, then wouldn't such data be host/build time specific 
>> and as such the classes that need to be enrolled into the default CDS 
>> archive of the JDK should be very selective (by reviewing what they 
>> do in their static init)? Like I said, I haven't looked into this in 
>> detail so perhaps it already is selective in the JDK build?
>>
>
> Hi Jaikiran,
>
Thank you very much for the detailed response.

> CDS also has the ability to archive Java heap object. Since 
> https://bugs.openjdk.java.net/browse/JDK-8244778 , we have archived 
> the entire module graph to improve start-up time. At run time, the 
> module graph (as well as other archived heap objects) are loaded from 
> the CDS archive and put into the Java heap (either through memory 
> mapping or copying).

That is interesting and something that I hadn't known.

>
> You can see the related code in 
> jdk.internal.module.ModuleBootstrap::boot()
I just had a look at it and it's quite elaborate and it'll take a me 
while to fully grasp it (if at all) given its understandable complexity.
>
> When the module system has started up, the module graph will reference 
> a copy of the OPEN enum object that was created as part of the 
> archive. However, the Modifier.<clinit> will also be executed at VM 
> start-up, causing a second copy of the OPEN enum object to be stored 
> into the static field Modified::OPEN.

Thank you for that detail. That helps me understand this a bit more (and 
opens a few questions). To be clear - the VM startup code which creates 
that other copy, ends up creating that copy because that piece of 
initialization happens even before the module system has fully started 
up and created those references from the archived state? Otherwise, the 
classloaders I believe would be smart enough to not run that static init 
again, had the module system with that graph from the archived state 
been fully "up"?

So would this mean that this not just impacts enums but essentially 
every class referenced within the module system (of just boot layer?) 
that has state which is initialized during static init? To be more 
precise, consider the very common example of loggers which are typically 
static initialized and stored in a static (final) field:

private static final java.util.logger.Logger logger = 
Logger.getLogger(SomeClass.class);

If the boot layer module graph has any classes which has state like 
this, it would then mean that if such classes do get initialized very 
early on during VM startup, then they too are impacted and the module 
graph holding instances of such classes will end up using a different 
instance for such fields as compared to the rest of the application code?

In essence, such classes which get accessed early (before module system 
with the archived graph is "up") during VM startup can end up 
_virtually_ having their static initialization run twice (I understand 
it won't be run twice, but that's the end result, isn't it)?

-Jaikiran



More information about the core-libs-dev mailing list