JDK-8288064 : Class initialization locking
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 20
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2022-06-08
  • Updated: 2024-08-07
  • Resolved: 2022-06-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 20
20 b03Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Currently, the JVM takes out a hidden Object lock while linking and while calling class initializers.  The Object lock is injected in the Java mirror so that class initializers have no visibility to it and cannot unlock it.  This lock is an Object so that we can hold it across upcalls to Java.  We cannot hold VM Mutex/Monitor locks across upcalls to Java.

There's code to remove this Object lock when initialization is complete so that it doesn't use space in the Java heap.  When InstanceKlass used to be in PermGen, this Object lock was simply the klassOop.

For the Object Monitors in Java project (moving synchronized support to Java), this init_lock Object taken in the VM will cause Java code to run while we're locking in order to link and initialize classes, and possibly the classes used for Java Object Monitor code itself.  Also JVMTI events and bytecode tracing needs to be disabled for this VM->Java locking code, since the application shouldn't know this detail.

It's not a difficult change to make the init_lock be a JVM native Monitor that's taken and held to set InstanceKlass initialization state, and used to wait while another thread is linking and initializing the class.  This would remove the problem of calling into Java in order to acquire a lock for mutual exclusion of linking and initializing classes.
Comments
Note this change is reverted by JDK-8333542
07-08-2024

Great! Thanks [~coleenp]!
16-06-2022

Changeset: cf4a4966 Author: Coleen Phillimore <coleenp@openjdk.org> Date: 2022-06-16 12:38:06 +0000 URL: https://git.openjdk.org/jdk/commit/cf4a4966a846ebea7e07c4ee6387fbf1081ea385
16-06-2022

From the test TestThreadDumpClassInitMonitor.java. Before: "TestThread" #34 [23495] prio=5 os_prio=0 cpu=0.55ms elapsed=0.82s tid=0x00001549f4023930 nid=23495 in Object.wait() [0x0000154a3a10c000] java.lang.Thread.State: RUNNABLE Thread: 0x00001549f4023930 [0x5bc7] State: _at_safepoint _at_poll_safepoint 0 JavaThread state: _thread_blocked at TestThreadDumpClassInitMonitor$Target$1.run(TestThreadDumpClassInitMonitor.java:93) - waiting on the Class initialization monitor for TestThreadDumpClassInitMonitor$Target After: "TestThread" #34 [6402] prio=5 os_prio=0 cpu=1.09ms elapsed=0.85s tid=0x0000146e1c028710 nid=6402 waiting on condition [0x0000146e62c77000] java.lang.Thread.State: RUNNABLE Thread: 0x0000146e1c028710 [0x1902] State: _at_safepoint _at_poll_safepoint 0 JavaThread state: _thread_blocked at TestThreadDumpClassInitMonitor$Target$1.run(TestThreadDumpClassInitMonitor.java:93) - waiting on the Class initialization monitor for TestThreadDumpClassInitMonitor$Target
15-06-2022

[~coleenp] can you add an example of how the stacktrace now looks when blocked waiting for a class to be initialized - thanks.
14-06-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/9141 Date: 2022-06-13 17:02:44 +0000
13-06-2022

>> I guess the object monitor initialization code has to be moved up for class loading also, right now. I'm not sure why that's not a problem for JDK-8287982. >I don't know what you mean by this. Never mind. We only take out the ObjectLocker when loading classes from non-parallel capable user-defined class loaders, ie. the bootstrap classes like Thread will already be loaded before we try to take this lock. > Is CDS loading pre-initialized classes these days? No, it's not. Still dubious to me. We took out conditional is_mt() locking years ago, which we presumably wouldn't have done if it helped performance. Moving from ObjectLocker to MutexLocker (native) didn't have any performance benefit even though it executes a lot less code.
13-06-2022

> I guess the object monitor initialization code has to be moved up for class loading also, right now. I'm not sure why that's not a problem for JDK-8287982. I don't know what you mean by this. > I doubt noop-ing the ObjectLocker for startup would have any benefit for performance because we have CDS. Feels unworthy of conditional code. Is CDS loading pre-initialized classes these days?
13-06-2022

Yes, for initialization, it's fairly simple to change it to a mutex and I used the same approach for linking in my patch. For linking, we lock the init_lock, not the loader-lock. The loader-lock is another issue. I guess the object monitor initialization code has to be moved up for class loading also, right now. I'm not sure why that's not a problem for JDK-8287982. I doubt noop-ing the ObjectLocker for startup would have any benefit for performance because we have CDS. Feels unworthy of conditional code.
10-06-2022

> If Object locking is moved to Java code, this init_lock taken in the VM will cause Java code to run while we're initializing classes, and possibly the classes used for Java Object Monitor code. The classes involved in the Java Object Monitor code have to be pre-loaded and pre-initialized very early in VM startup. In addition to avoid the kind of problems described we can making locking a no-op whilst VM initialization is still single-threaded. This is currently done for linking and initialization. But if we can eradicate some of that use of Object Monitors then it will make things easier. Note that making the locking a no-op during VM init is an optimisation that could be applied today - no idea if it has any noticeable affect on startup though. Also note that for initialization we don't actually hold the Object Monitor across the Java upcall - so using a mutex is not an issue for class init. However we do hold it during linking which can lead to classloading and thus Java calls. If the locking during linking is purely to ensure only one thread links a given class then we could use a similar technique as for class-init and just mark the class as being linked, forcing other threads to wait; then do a notify when linking is over. It is unclear to me how locking the loader-lock for linking is expected to interact with the locking applied by the class loading code itself.
10-06-2022