Speed up Android build times with simple tweaks to the Java Development Kit and Gradle. After benchmarking build times for 3 projects with different JDK versions, JDK 17 is now also preinstalled on all build stacks to help you get the 9-20% speed improvements we did. Learn more and try them!
Gradle and the Android tooling run on Java, and the minimum required JDK (Java Development Kit) version to run these tools is 11 at the moment, and this is the default on Bitrise stacks as well. JDK11 is 3 years old though, and the current LTS (Long Term Support) release is JDK17.
The inspiration for this experiment was an article about the performance improvement of recent JDK versions. We benchmarked the performance of JDK11 and JDK17 on Android builds with the default settings, then with an alternative garbage collector enabled.
Based on the results we decided to preinstall JDK 17 on the build stacks (both Linux and macOS), so you can benefit from the improvements (JDK 11 remains the default though).
The JDK version used for running Gradle does not affect the final application in any way. The Java runtime on an Android device is independent of the runtime used to build the app on a developer machine. An app built with Gradle running on JDK17 can still run on Android devices with earlier runtimes (because 'minSdkVersion' and 'compileSdkVersion' controls the app’s behavior)
Changing the JDK version and the garbage collector are relatively quick tasks to improve build speeds compared to huge refactors or other long initiatives. There are a few requirements to keep in mind though:
JDK17 on Bitrise VMs
We decided to preinstall JDK 17 on the build stacks (both Linux and macOS), so you don’t have to install it manually and lose time waiting for the process. JDK 11 is still the one activated by default, but you can use our step to activate JDK 17.
Minimum Gradle version: 7.3
The first Gradle version that officially supports Java 17 is version 7.3. You might need to upgrade Gradle in your project in the 'gradle-wrapper.properties' file to start using JDK17.
Minimum Kotlin version: 1.5.30
Earlier Kotlin versions are incompatible with JDK 17 because of this bug.
Besides these changes, you might have other plugins and tools in the project that need an update for JDK 17.
The default garbage collector for both JDK11 and JDK17 is called G1. There are other garbage collectors that are part of JDK though, and these can be enabled with a command-line flag. The Parallel garbage collector is available for both JDK versions, and it seems to be ideal for the workload of a compiler (where throughput and memory footprint is more important than latency).
To change the garbage collector from the default G1 to Parallel, you need to add the '-XX:+UseParallelGC' flag to the 'gradle.properties' file:
We tested the build time of open-source Android projects running on Bitrise with multiple JDK configs. Build time was measured with the gradle-profiler project on Linux EliteXL Bitrise build machines. See the end of this article for more details about the benchmark setup.
Open-source apps used for benchmarking:
The baseline for the comparisons is running Gradle on JDK11 with its default garbage collector, G1. The relative improvements are compared to this config.
For the Tivi project, we measured a 16% improvement switching to the Parallel garbage collector while still running on JDK11. Switching to JDK17 and the Parallel GC resulted in a 20% speedup!
Building Firefox on JDK11 with Parallel GC was 5% faster and using Parallel GC on JDK17 is a 12% improvement compared to the baseline.
For the DuckDuckGo project, the percentages are a bit lower, but the pattern is the same as before. Switching to the Parallel GC on JDK11 makes builds 4% faster, switching to JDK17 with Parallel GC is a 9% improvement.
Across the three sample apps benchmarked, we see nice build speed improvements with relatively low effort changes:
- Keep using JDK11, switch to Parallel GC: 4-16%
- Upgrade to JDK17, no change to GC: 6-14%
- Upgrade to JDK17, switch to Parallel GC: 9-20%
For the benchmark we used a fork of every sample app where we made some changes:
- Upgraded Gradle to 7.3
- Upgraded Android Gradle Plugin as well if needed
- Disabled both remote and local Gradle caching if it was enabled in the original project
Build times were measured with Gradle Profiler with the following config:
- Warm-ups: 1
- Iterations: 5
- Restarting Gradle daemon between builds
- Running the 'clean' task between builds
The warm-up task downloaded and cached dependencies to '~/.gradle', so the subsequent build measurements were not skewed by network requests.
Run your own benchmark on Bitrise
We encourage you to run the same benchmarks to see the exact numbers for your project. For reference, here is the full workflow used for the benchmarks:
Benchmark results are deployed as build artifacts in CSV and HTML format, so you can process the raw data later or view the report instantly on Bitrise: