Skip to content

Add Gauges for memory usage after GC#7296

Draft
shakuzen wants to merge 3 commits intomicrometer-metrics:mainfrom
shakuzen:mem-after-gc
Draft

Add Gauges for memory usage after GC#7296
shakuzen wants to merge 3 commits intomicrometer-metrics:mainfrom
shakuzen:mem-after-gc

Conversation

@shakuzen
Copy link
Copy Markdown
Member

@shakuzen shakuzen commented Mar 16, 2026

See https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmmemoryused_after_last_gc.

Register gauges in JvmMemoryMetrics and add MeterConvention for it.

Sample scrape output in Prometheus format with the default convention:

# HELP jvm_memory_used_after_last_gc_bytes Measure of memory used, as measured after the most recent garbage collection event on this pool.
# TYPE jvm_memory_used_after_last_gc_bytes gauge
jvm_memory_used_after_last_gc_bytes{area="heap",id="G1 Eden Space"} 0.0
jvm_memory_used_after_last_gc_bytes{area="heap",id="G1 Old Gen"} 1.7567952E7
jvm_memory_used_after_last_gc_bytes{area="heap",id="G1 Survivor Space"} 6643856.0

With the OpenTelemetry convention configured:

# HELP jvm_memory_used_after_last_gc_bytes Measure of memory used, as measured after the most recent garbage collection event on this pool.
# TYPE jvm_memory_used_after_last_gc_bytes gauge
jvm_memory_used_after_last_gc_bytes{jvm_memory_pool_name="G1 Eden Space",jvm_memory_type="heap"} 0.0
jvm_memory_used_after_last_gc_bytes{jvm_memory_pool_name="G1 Old Gen",jvm_memory_type="heap"} 1.6742336E7
jvm_memory_used_after_last_gc_bytes{jvm_memory_pool_name="G1 Survivor Space",jvm_memory_type="heap"} 5308896.0

@shakuzen shakuzen added enhancement A general enhancement module: micrometer-core An issue that is related to our core module instrumentation An issue that is related to instrumenting a component labels Mar 16, 2026
@shakuzen shakuzen added this to the 1.17.0-RC1 milestone Mar 16, 2026
*
* @author Michael Weirauch
*/
@Tag("gc")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured it is worth running these tests with different GC configurations to ensure there are no surprises.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use @GcTest which is equivalent.


JvmMemoryMeterConventions.JvmMemoryUsedAfterLastGcConvention memoryUsedAfterLastGcConvention = conventions
.getMemoryUsedAfterLastGcConvention();
if (memoryPoolBean.getCollectionUsage() != null) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did have a version of this code that registered pools even if this returns null, but they always have the value NaN which didn't seem worthwhile registering.

*
* @since 1.17.0
*/
interface JvmMemoryUsedAfterLastGcConvention extends MeterConvention<MemoryPoolMXBean> {
Copy link
Copy Markdown
Member Author

@shakuzen shakuzen Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if it would be better to make this a top level type - it can be a bit annoying to reference it as JvmMemoryMeterConventions.JvmMemoryUsedAfterLastGcConvention, but maybe it also logically groups what would be the individual convention types (if we had them for the other conventions here, that is).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grouping makes sense to me. Not sure how well-known it is but if people annoyed by using JvmMemoryMeterConventions.JvmMemoryUsedAfterLastGcConvention, they can static import it:

import static io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions.JvmMemoryUsedAfterLastGcConvention;

and use only JvmMemoryUsedAfterLastGcConvention like it would be a top-level type.

* @return convention for JVM memory used after last GC
* @since 1.17.0
*/
default JvmMemoryUsedAfterLastGcConvention getMemoryUsedAfterLastGcConvention() {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While other methods here have return type MeterConvention<MemoryPoolMXBean>, that was probably a mistake that I tried to not repeat here. In a framework's configuration model, it would be reasonable for there to be a way for a user to provide a custom convention for a specific convention, and that's made harder by using generic types that do not uniquely identify a single convention.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we create an issue for 2.x?


@Override
default Tags getTags(MemoryPoolMXBean memoryPoolBean) {
return Tags.empty();
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default implementation is not useful, but it was needed since we can't add a new non-default method to the JvmMemoryMeterConventions interface without breaking types that extend/implement it.

@shakuzen shakuzen requested a review from jonatan-ivanov March 16, 2026 03:13
@shakuzen
Copy link
Copy Markdown
Member Author

It's perhaps worth mentioning that there is a similarly named existing gauge for the calculated value of post-GC heap usage percentage:

# HELP jvm_memory_usage_after_gc The percentage of long-lived heap pool used after the last GC event, in the range [0..1]
# TYPE jvm_memory_usage_after_gc gauge
jvm_memory_usage_after_gc{area="heap",pool="long-lived"} 0.0019396338611841202

Maybe it makes sense to deprecate that in lieu of this newly added metric.

@jonatan-ivanov
Copy link
Copy Markdown
Member

Maybe it makes sense to deprecate that in lieu of this newly added metric.

I think so, I'm also thinking to disable it by default in the future and make it possible to the users to re-enable it.

@shakuzen
Copy link
Copy Markdown
Member Author

I opened #7311 for introducing a proper deprecation concept. Until then, let's start with just mentioning the deprecation in the description of the deprecated meter.

@shakuzen shakuzen modified the milestones: 1.17.0-RC1, 1.18.x Apr 2, 2026
@shakuzen shakuzen marked this pull request as draft April 2, 2026 10:30
@shakuzen
Copy link
Copy Markdown
Member Author

shakuzen commented Apr 2, 2026

I've moved this to 1.18 and made it a draft PR. I want to figure out what we plan to do going forward with the meter conventions (current draft #7369) before adding this. I suppose we could add it first without a convention to avoid tackling that issue, but also no one asked for this, so it doesn't seem high priority either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement A general enhancement instrumentation An issue that is related to instrumenting a component module: micrometer-core An issue that is related to our core module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants