DEV Community

Cover image for Using ParallelGC for the Kotlin process in Android Builds
Iñaki Villar
Iñaki Villar

Posted on • Updated on

Using ParallelGC for the Kotlin process in Android Builds

tl;dr

  • The type of garbage collector is not inherited by the Kotlin process if it's specified by the jvmargs property
  • When comparing ParallelGC for the Kotlin process against G1, the experiment showed:
    • 22% Kotlin Compile aggregated task time improvement
    • 60% garbage collector time improvement of the Kotlin process
    • 51% usage reduction of the Kotlin process memory usage
  • The results are based on ephemeral agents(CI) builds. Please, before adopting this type of configuration, measure your builds!

Context

The idea for this article was born when investigating the behavior of the JVM arguments in the Kotlin process in Android builds. The theory says if no argument were specified for the Kotlin process, it inherits the arguments from the Gradle daemon, given:

org.gradle.jvmargs=-Xmx500m
Enter fullscreen mode Exit fullscreen mode

We will retrieve the PID for the process:

 jps | grep KotlinCompileDaemon | sed 's/KotlinCompileDaemon//' | xargs jinfo
Enter fullscreen mode Exit fullscreen mode

The result is:

VM Flags:
-XX:MaxHeapSize=528482304 
Enter fullscreen mode Exit fullscreen mode

However, when we set the type of collector like:

org.gradle.jvmargs=-Xmx3g  -XX:+UseParallelGC
Enter fullscreen mode Exit fullscreen mode

The Garbage collector defined for the Kotlin process is:

 -XX:+UseG1GC
Enter fullscreen mode Exit fullscreen mode

In this case, we need to declare the type of GC for the Kotlin process explicitly:

kotlin.daemon.jvmargs=-Xmx3g -XX:+UseParallelGC
Enter fullscreen mode Exit fullscreen mode

And is here where I noticed that the references in terms of JVM arguments optimizations are always focused on the Gradle process without discussing one of the main components of our builds: The Kotlin process.

This article explains the results of measuring the different combinations of Garbage Collectors in the Gradle/Kotlin processes.

Experiment

Environment

  • Linux 5.15.0-1035-azure (amd64)
  • 2 CPU cores
  • 2 Gradle workers
  • 3 Gb memory heap size
  • Github Action agent

Project

Experiment Variants

id Gradle GC Kotlin GC
gg_kg G1 G1
gp_kg ParallelGC G1
gg_kp G1 ParallelGC
gp_kp ParallelGC ParallelGC

Methodology

  • Each variant runs 40 Gradle profiler scenarios
  • Each scenario runs one warm-up and five builds
  • Each scenario applies a Gradle profiler scenario with an abi change on the module core:datastore(Highest betweenness centrality in the project dependency graph).
  • The task executed for each scenario is clean :app:assembleDebug
  • This type of scenario generates for each execution:
    • 512 tasks executed in 25 projects
    • 24 Kotlin Compiler tasks executed in 12 projects
    • 26 Java Compiler tasks executed in 12 projects
  • We have ignored the warm-up and first build in all the results of each execution

Results

We have grouped the results by:

  • Build duration
  • Kotlin Compile tasks duration
  • GC time by the Kotlin process
  • Usage of the Kotlin process

Builds

The data was extracted from the outputs generated for each Gradle Profiler execution, duration in milliseconds

Image description

Mean by variant

Image description

Kotlin Compiler

We aggregated the build time of Kotlin Compiler tasks with the outcome "SUCCESS" using Gradle Enterprise API, duration in milliseconds:

Image description

Mean by variant

Image description

Kotlin process

Using the Plugin InfoKotlin process, we retrieved the information of the Kotlin process on the last build of the profiled scenario for each execution
GC Time
Garbage Collector time in minutes:
Image description

Mean by variant

Image description

Usage
Kotlin process usage in GB:
Image description

Mean by variant

Image description

Final words

In this experiment using ParallelGC in the Kotlin process, we showed the benefits over G1.
Again, the goal of this article is not to give you a reason to create a PR using ParallelGC. You need to measure what matters in your project, CI pipelines could contain expensive builds with R8 tasks or endless test tasks, and we just covered assembleDebug.

Finally, as you know, with AGP 8, JDK is set to 17. I will publish a new article covering this experiment with the JDK 17 Garbage collector results.

Happy Building!

Top comments (0)