Since JDK 5 the Oracle/OpenJDK support an internal sun.management.HotspotInternal
MBean which exports the five HotspotClassLoading
, HotspotCompilation
, HotspotMemory
, HotspotRuntime
and HotspotThreading
MBeans from the sun.management
package. See ManagementFactoryHelper::registerInternalMBeans()
for how and where these MBeans are registered. Notice that these MBeans are not installed by default in the platform MBeanServer
, this has to be done manually with (see InternalMBeans.java in this Gist for a full example):
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.createMBean("sun.management.HotspotInternal", null);
These MBeans mostly source their data from HotSpot's perfromace counters (see sun.management.VMManagementImpl::getInternalCounters() and jdk.internal.perf.Perf for how it is implemented). Notice that writing the hsperf
counters might have perfromance impacts in some rare situations (you can read my investigations "Performance implications of -XX:+/-PerfDisableSharedMem
" for more details).
Since the modularization of the JDK in JDK 9, the sun.management
package is not exported any more from the java.management
module where it lives in. However it was still possible to use it (albeit at the cost of a " illegal reflective access" warning). Since the implementation of strong encapsualtion in JDK 17, the usage of the sun.management
MBeans require the usage of the --add-exports java.management/sun.management=ALL-UNNAMED
command line paramter.
Using the sun.management
MBeans in JConsole
requires the usage of the J-Djconsole.showUnsupported=true
command line paramter (and --add-exports java.management/sun.management=ALL-UNNAMED
in the monitored target VM). You can then choose HotSpot MBeans
from the Connection
menue to create the internal HotSpot MBeans in the target VM.
Following are the contents of an email I wrote to the core-libs-dev mailing list
I recently looked for an easy way to get the CPU time spent by JIT-compiler and GC threads in Java (e.g exported by IBM J9's JvmCpuMonitorMXBean [0]). An easy way to achieve this is in OpenJDK is by using the "sun.management.HotspotInternal" MBean which exports the "sun.management:type=HotspotThreading" MBean with the attributes InternalThreadCount/InternalThreadCpuTimes (among other useful HotSpot internal counters and metrics).
Up until JDK 16/17 the usage of the "sun.management.HotspotInternal" MBean was straightforward, although it resulted in an illegal reflective access warning since JDK 9. Since JDK 17 its usage requires the " --add-exports java.management/sun.management=ALL-UNNAMED" for the monitored JVM.
I wonder why "sun.management" was encapsulated in the first place? I understand that it is not an "officially supported" API, but I find it still quite useful. If we really don't want to export it, I wonder why we are maintaining it at all (we even have JTreg tests for it under "test/jdk/sun/management"), because in the current configuration it isn't particularly useful.
Notice that jconsole supports the "sun.management.HotspotInternal" MBean if started with "J-Djconsole.showUnsupported=true" and the "java.management" module kind of tries to support jconsole with the following exports:
exports sun.management to jdk.jconsole, jdk.management, jdk.management.agent;
However, that doesn't help even if jconsole monitors itself (for the general case, where jconsole monitors a different JVM process it can't work anyway). With JDK 16 and "--illegal-access=debug" we can see why:
WARNING: Illegal reflective access by sun.reflect.misc.Trampoline to method sun.management.HotspotThreadMBean.getInternalThreadCount() at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71) at java.base/sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:260) at java.management/com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:112) at java.management/com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:46) at java.management/com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:237) at java.management/com.sun.jmx.mbeanserver.PerInterface.getAttribute(PerInterface.java:83) at java.management/com.sun.jmx.mbeanserver.MBeanSupport.getAttribute(MBeanSupport.java:206) at java.management/com.sun.jmx.mbeanserver.MBeanSupport.getAttributes(MBeanSupport.java:213) at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttributes(DefaultMBeanServerInterceptor.java:701) at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.getAttributes(JmxMBeanServer.java:705)
Notice that
sun.reflect.misc.Trampoline
is loaded by a custom class loader (java.base/sun.reflect.misc.MethodUtil
) and not considered part of the base module.So to cut a long story short, I see several options:
- Publicly export sun.management and restore the JDK 8 (or pre JDK 16) behavior. This would certainly require some polishing (e.g. some of the corresponding JVM functionality has already been removed [1]) but I think it could still be quite useful.
- Port the useful functionality from the "sun.management" MBeans to corresponding "com.sun.management" MBeans and remove the "sun.management" MBeans.
- Remove the "sun.management" MBeans without substitution.
What do you think?
Thank you and best regards, Volker
[0] https://www.ibm.com/docs/en/sdk-java-technology/8?topic=interfaces-language-management
You can read the whole thread but the overall feedback was that Oracle more or less favours option three from above, i.e. rather completely remove the internal mbeans than making them publicly available.
I think that's sad because these internal MBeans together with the hsperf counters offer a very low-overhead way of monitoring JVM internals which are not available from other sources.
- There exist some JTReg tests for the internal
sun.management
MBeans undertest/jdk/sun/management/
. Notice that these tests also require the corresponding--add-exports
flag which is injected throughtest/jdk/sun/management/TEST.properties
. This was initially added by JDK-8078896: Add @modules as needed to the jdk_svc tests in JDK 9. - JDK-8134607: Remove per-compiler performance counters removed the
sun.ci.compilerThread.#.{compiles, method, time, type}
hsperf counters in JDK 9. The corresponding Java class undersrc/java.management/share/classes/sun/management/CompilerThreadStat.java
were still in place until JDK 23 where it was removed by JDK-8328341: Remove deprecated per-thread compiler stats in sun.management. - JDK-8315149: Add hsperf counters for CPU time of internal GC threads added by Google in JDK 22.