Gradle plugin that collects GC metrics based on the GC logs generated during the build. Apply it from settings (preferred) or from a project build script. If Develocity is configured in the build, the plugin publishes GC metrics as custom values. Otherwise, it generates a console report and a CSV file.
Analyzing the types of garbage collections that occurred during the build can provide valuable insights into performance issues.
This plugin is intended for performance investigations and is not meant to be enabled in regular builds.
- Gradle: 8.9+. The plugin obtains
BuildEventsListenerRegistryvia constructor injection (@Inject) and registers a build service that listens for task completion. - Java: 17+. Published plugin bytecode is pinned with
jvmToolchain(17)ingradle-plugin/build.gradle.kts, so the class-file target does not depend on which JDK runs the release build. The Gradle daemon that loads the plugin must therefore run on Java 17 or newer. - GC collectors / log formats: Unified JVM logging (
-Xlog:gc*, as in the examples below). Test fixtures cover G1 and Parallel. Other collectors (for example ZGC) are not validated. - Application target:
io.github.cdsap.gcreportworks insettings.gradle/settings.gradle.kts(preferred) and in project build scripts (build.gradle/build.gradle.kts). Build-service registration and Develocity hooks run once per build, including multi-project builds. See Applying from a build script. - Configuration cache / Isolated Projects: Both plugin ids declare Configuration Cache support.
io.github.cdsap.gcreportalso declares Isolated Projects support when applied from settings; applied from a subproject build script it is not Isolated Projects compatible (see Applying from a build script). The project-only aliasio.github.cdsap.gcreport.projectdeclares Isolated Projects as unsupported.
Plugin id / marker: io.github.cdsap.gcreport (current version 0.1.1).
Kotlin (settings.gradle.kts):
plugins {
id("io.github.cdsap.gcreport") version "0.1.1"
}
gcReport {
logs.set(listOf("gradle_gc.log"))
gbosEnabled.set(true)
}Groovy (settings.gradle):
plugins {
id 'io.github.cdsap.gcreport' version '0.1.1'
}
gcReport {
logs = ['gradle_gc.log']
}org.gradle.jvmargs=-Xlog:gc*:file=/project/gradle_gc.loggcReport {
logs.set(listOf("gradle_gc.log"))
gbosEnabled.set(true)
}
GBOS output is disabled by default. Enable all GBOS sinks this plugin supports
with a single switch — either the DSL gbosEnabled or the Gradle property:
gcReport.gbos.enabled=trueWhen enabled, the plugin writes both build/reports/gcreport/gbos.json and
build/reports/gcreport/gbos.ndjson. The JSON sink is a GBOS report envelope;
NDJSON contains one complete observation per line. Files are replaced atomically
after successful generation, and are removed when GBOS is disabled or no
observations are available.
With Develocity present, the same switch also publishes the GBOS observations as
Build Scan custom values and replaces legacy gc-* custom values (including the
histogram value). Console output, CSV files, and log processing remain unchanged.
| Develocity present | gbosEnabled |
Develocity custom values |
|---|---|---|
| no | any | none |
| yes | false | legacy gc-* values (and histogram when enabled) |
| yes | true | GBOS observations only |
If your project involves multiple JVM processes, such as Gradle and Kotlin, you can configure the plugin to collect GC metrics from all of them by specifying multiple log files.
For example, to capture GC logs from both Gradle and Kotlin daemon processes, configure their JVM arguments as follows:
org.gradle.jvmargs=-Xlog:gc*:file=/project/gradle_gc.log
kotlin.daemon.jvmargs=-Xlog:gc*:file=/project/kotlin_gc.log
Then, update the plugin configuration to process both logs:
gcReport {
logs.set(listOf("gradle_gc.log","kotlin_gc.log"))
}This ensures that GC metrics from both the Gradle build process and the Kotlin daemon are captured and analyzed.
┌──────────────────────────────────────────────────────────────────────┐
│ GC Log: gc.log │
├────────────────────────────────────────────────────────┬─────────────┤
│ Collection type │ Occurrences │
├────────────────────────────────────────────────────────┼─────────────┤
│ Pause Young (Normal) (G1 Evacuation Pause) │ 6 │
├────────────────────────────────────────────────────────┼─────────────┤
│ Pause Young (Concurrent Start) (Metadata GC Threshold) │ 4 │
├────────────────────────────────────────────────────────┼─────────────┤
│ Pause Young (Prepare Mixed) (G1 Evacuation Pause) │ 3 │
├────────────────────────────────────────────────────────┼─────────────┤
│ Pause Young (Mixed) (G1 Evacuation Pause) │ 3 │
├────────────────────────────────────────────────────────┼─────────────┤
│ Concurrent Mark Cycle │ 4 │
└────────────────────────────────────────────────────────┴─────────────┘
Collection type,Occurrences
Pause Young (Normal) (G1 Evacuation Pause),8
Pause Young (Concurrent Start) (Metadata GC Threshold),4
Pause Young (Prepare Mixed) (G1 Evacuation Pause),1
Pause Young (Mixed) (G1 Evacuation Pause),1
Concurrent Mark Cycle,4
The plugin can generate histograms from the GC log data. This is useful for visualizing the distribution of GC events over time.
You can configure the histograms by setting the histogram property in the gcReport extension:
gcReport {
logs.set(listOf("$gcLog"))
histogramEnabled.set(true)
histogramBucket.set(Bucket.SquareRoot)
}There are three bucket types available:
Bucket.SquareRoot- Uses the square root of the number of elements to determine the number of bins, often used for small datasets.Bucket.Sturges- Uses Sturges' formula, which works well for normally distributed data.Bucket.FreedmanDiaconis- Adapts the bin width based on data variability, useful for datasets with high variance.
When enabling this option, the plugin will generate a histogram entry in Develocity as a custom value or a new CSV file:
Bucket,Occurrences
0.00-1.23,4
1.23-2.46,3
2.46-3.69,4
3.69-4.92,3
4.92-End,1
Prefer applying io.github.cdsap.gcreport from settings so configuration and build-service registration happen once for the whole build.
Existing builds that apply the plugin from a project build.gradle(.kts) keep working with the same id:
plugins {
id("io.github.cdsap.gcreport") version "0.1.1"
}
gcReport {
logs.set(listOf("gradle_gc.log"))
}io.github.cdsap.gcreport.project is a project-only alias of the same plugin and is not needed for new builds.
Configure GCReport in one place per build. Registration is guarded to run once: if the plugin is applied from settings and also from a build script, the settings gcReport { } block is used and the build-script block is ignored.
Applying the plugin from a subproject build script is not compatible with Isolated Projects. The plugin reads the root project's layout (report directory) and extensions (Develocity lookup), and Isolated Projects rejects that cross-project access. Apply it from settings when using org.gradle.unsafe.isolated-projects=true.
- Supported GC collectors and log formats are listed under Compatibility.
- The plugin output may be unreliable for incremental builds where log rotations have occurred.
