JDK-8368529 : JMX: Add an MXBeans method to query GC CPU time
  • Type: CSR
  • Component: core-svc
  • Sub-Component: java.lang.management
  • Priority: P4
  • Status: Finalized
  • Resolution: Unresolved
  • Fix Versions: 26
  • Submitted: 2025-09-24
  • Updated: 2025-10-31
Related Reports
CSR :  
Description
Summary
-------
Add a method to `java.lang.management.MemoryMXBean` to return the accumulated CPU time in nanoseconds for GC related activity.

Problem
-------
The HotSpot VM supports retrieval of GC CPU time since JDK 26 (JDK-8359110) and logs these values via `-Xlog:cpu` during VM shutdown. To support a refined understanding, during critical sections, of GC CPU time, sampling this at will is needed. There is no viable alternative to sample this from Java application code or JMX tooling today.

Solution
--------

Add method to `java.lang.management.MemoryMXBean.getTotalGcCpuTime()` to return a `long` result with the accumulated CPU time in nanoseconds for GC related activity.

Alternative solutions have been explored, including adding to the standard and JDK-specific `GarbageCollectorMXBean` interfaces. These interfaces are ill-suited to this "property" as they don't model GC in the whole. Introducing a new JDK-specific management interface was also explored.

The proposal addition allows for VM implementations that do not support this feature.

Although added as a standard API, possibly usage may be in conjunction with the `ProcessCpuTime` property defined by the JDK-specific management interface `com.sun.management.OperatingSystemMXBean`.

A release note will be added.

Specification
-------------

```
    /**
     * Returns the approximate accumulated time, in nanoseconds,
     * spent in garbage collection (GC).
     *
     * <p> The time spent in spent in GC is the CPU time used by
     * all GC activity, including any overhead, which means the
     * result may be non-zero even if no GC has occurred.
     *
     * This method returns {@code -1} if the platform does
     * not support this operation or the information is not
     * available.
     *
     * @apiNote
     * May be used in conjunction with {@link jdk.management/com.sun.management.OperatingSystemMXBean#getProcessCpuTime()}
     * for calculating the GC's usage of CPU time as a whole.
     *
     * @implNote The specifics on what constitutes the time spent
     * in GC are highly implementation dependent. In the HotSpot
     * Virtual Machine, this time includes relevant
     * implementation-specific details such as driver threads,
     * workers, VM Operations and string deduplication (if
     * enabled). Driver threads may be created by a GC to
     * orchestrate its work. The return value can be -1 if called
     * when measurement is not possible, such as during shutdown.
     *
     * @implSpec The default implementation returns {@code -1}.
     *
     * @return the total accumulated CPU time for GC in
     * nanoseconds, or {@code -1}.
     *
     * @since 26
     */
    default long getTotalGcCpuTime() { .. }
```


Comments
Yes, I was trying to say that a jdk.management.SomeMXBean extending a java.lang one would be new and surprising. (jdk.management package!)
30-10-2025

Not quite true that "jdk.management has been used for all-new MBeans, not variations of a java.lang interface". com.sun.management includes direct java.lang.management extensions of GarbageCollectorMXBean, OperatingSystemMXBean, and ThreadMXBean. And UnixOperatingSystemMXBean as an extension of OperatingSystemMXBean.
30-10-2025

Looks good I think. If you want to expand this line: "While it could have been added as a JDK-specific bean we do not want to increase com.sun.management. There is no jdk.management bean for this method so introducing a new one just for this method might introduce unnecessary confusion. This leads to putting this method in java.lang.management.MemoryMXBean." Just to check we're in sync, I think this is the reasoning: "While this could have been added in a JDK-specific MXBean, unlike some interfaces there is no existing com.sun.management interface for MemoryMXBean. It is desirable to not introduce new MBeans in com.sun.management where possible, and adding a MemoryMXBean in jdk.management may introduce unnecessary confusion (jdk.management has been used for all-new MBeans, not variations of a java.lang interface). The new method is a good fit for java.lang.management.MemoryMXBean, with a default imlementation to avoid any unnecessary burden."
30-10-2025

I think it's hard to find an optimal solution for the placing of the new method but I like the proposed solution in `MemoryMXBean`. However, that changes the scope of this CSR from JDK to SE, so I've updated it. And once we're on it to do an SE-scope change, I strongly recommend to also add `getTotalCompilationCpuTime()` to ` CompilationMXBean` for basically the same reasons we add `getTotalGcCpuTime()` (even if getTotalCompilationCpuTime() will initially only return `-1` by default). The only downside of adding the new methods to an SE-covered class is that it will be impossible to downport this feature to an earlier JDK. But that's also a reason to immediately add `getTotalCompilationCpuTime()` (even if not implemented) because a potential implementation can easily be downported at any time.
30-10-2025

> In addition to gc(), the pair of verbose methods also applies to the GC as a whole in MemoryMXBean: They may be implemented through GC logging but they are specified at a higher-level as just "verbose output for the memory system". (And given the memory system includes non-heap memory it should probably involve more than just GC logging!) > the current contract in GarbageCollectorMXBean is to expose only sub-components What "contract" are you referring to? I find the current behaviour quite surprising to be honest as the things being exposed are not what I (with a lay person's hat on) would consider to be collectors per-se. But that ship has sailed and I don't think we can try and interpose a new MBean to represent the GC as a whole. On that topic I think there is (and should be) a high bar for adding new MXBeans and I agree with [~kevinw] that a CpuTimeMXBean is not really in-line with the general MXBean design philosophy. Something that provides information about GC should be a method in a GC-related bean IMHO. [~alanb] Who owns JMX these days? I would have gone to Mandy for guidance in the past.
30-09-2025

> What about getTotalGcCpuTime() to avoid conflating with process? Yes I do like that as well, although if it was in java/lang/management/GarbageCollectorMXBean then it could still look like total for a specific generation? getTotalProcessGcCpuTime is clearer but getting a bit long (if that's a bad thing). MemoryMXBean.getTotalGcCpuTime() would be clearer to me. MemoryMXBean "The management interface for the memory system". It clearly cuts across generations, is not as precise as to represent a specific GC generation or specific memory pool, and has the method to invoke gc. I see the dislike of using MemoryMXBean and these classes don't make it easy for us. We don't have a specific MXBean for each GC other than the one which is specific to a generation. We do have MemoryManagerMXBean but that does not look like the right place.
29-09-2025

I think a new CPUTimeMXBean would be more problematic. The Platform MXBeans are: ClassLoading, Memory, Thread, Runtime, OperatingSystem, PlatformLogging, Compilation, GarbageCollector, MemoryManager, MemoryPool, BufferPool. https://docs.oracle.com/en/java/javase/25/docs/api/java.management/java/lang/management/ManagementFactory.html#getPlatformMXBean(java.lang.Class) Attributes like CPU time used by a thing, are in the MXBean for the thing. New CPU time tracking should have an existing MXBean it can be placed in. We may have a lack of clarity on the roles of the GC/Memory beans, about whether MemoryMXBean is a high level overview, and whether GarbageCollectorMXBean is strictly about a specific generation or about a collector as a whole. Starting CPUTimeMXBean, where the MXBean is named after the attribue, and the new MXBean will contain getters for those attributes for all kinds of different areas? OperatingSystemMXBean.getProcessCpuTime(), ThreadMXBean has getCurrentThreadCpuTime() etc.. are established and we can't realistically move them, so we will either have them in two places, or the new CPUTimeMXBean has an unclear role. This must create a problem of where to put the getters, and confusion on where to find them.
29-09-2025

I had a discussion with [~sjohanss] (from the GC team) and since the current contract in `GarbageCollectorMXBean` is to expose only sub-components we think it is best for compatibility reasons to keep this interface implementation as is. Another possibility that [~sjohanss] suggested, (and that I think would be an excellent option over MemoryMXBean) is to introduce a new interface `CPUTimeMXBean`. We made a survey over the available platform managed beans and some are at a high abstraction level‚ while others like BufferPoolMXBean or ClassLoadingMXBean is at a seemingly lower level. This could also provide a more straightforward way to obtain the `getProcessCpuTime` method, which currently requires a type cast to com.sun.management.OperatingSystemMXBean. A sketch of the possible interface: ``` public interface CPUTimeMXBean extends PlatformManagedObject { public long getGcCpuTime(); public long getProcessCpuTime(); } ``` This also allow for reasonable place to consolidate any future additions to CPU time tracking of other VM components. > Could the new method getGcCpuTime() be called getProcessGcCpuTime(), to say that it's not generation-specific time being returned (inspired by the OperatingSystemMXBean cpu time methods). What about getTotalGcCpuTime() to avoid conflating with process?
29-09-2025

I don't think this is suitably placed in the `MemoryMXBean`. The `MemoryMXBean` is a fairly high-level abstraction dealing with memory pools and memory managers, with GC being a well-known memory manager for heap memory. Having a method that queries GC implementation details just seems out of place here. ( I'll also add the existing `gc()` method seems equally misplaced IMO.) Conceptually the `GarbageCollectorMXBean` seems the obvious location for this new method, alongside the existing `getCollectionCount()` and `getCollectionTime()`. In the PR Jonas argues that the way we define multiple "sub-system" `GarbageCollectorMXBean`s e.g.: ``` G1 Young Generation G1 Concurrent GC G1 Old Generation ``` makes them ill-suited for something that applies to the GC as a whole. I certainly see his point, as even the existing methods seem to be difficult to interpret against individual beans in some cases. But that does not make `MemoryMXBean` a more suitable location IMO. I think it is cleaner to define a `GarbageCollectorMXBean` method that applies to the collective GC.
29-09-2025

Thank you [~dholmes] for your review. > Having a method that queries GC implementation details just seems out of place here In addition to gc(), the pair of verbose methods also applies to the GC as a whole in MemoryMXBean: * setVerbose() -> calls the native method named setVerboseGC, which in turns set -Xlog:gc * isVerbose -> check if -Xlog:gc is set If we introduce a new GarbageCollectorMXBean that describe the GC as a whole for each GC in OpenJDK and add getGcCpuTime() to each, as an user I would expect to find the aforementioned methods (gc, setVerbose/isVerbose) in that interface too. However refactoring these methods may introduce compatibility risks. Given that there already is precedent and presumably a de-facto expectation that this interface do perform tasks for the GC as a whole (and no GarbageCollectorMXBean provide any means for the GC as a whole) in this method I think we could still consider the proposed approach in light of compatibility risks.
29-09-2025

Could the new method getGcCpuTime() be called getProcessGcCpuTime(), to say that it's not generation-specific time being returned (inspired by the OperatingSystemMXBean cpu time methods).
29-09-2025