jvmcache is a fast, transparent drop-in compiler cache for javac, kotlinc, kapt, d8, and r8, modeled after ccache and sccache.
It intercepts compiler invocations, hashes input sources, semantic compiler flags, and classpath dependencies, and restores compiled bytecode artifacts from content-addressable storage (CAS) in 1 to 10 milliseconds.
Evaluated against real-world, widely used open-source libraries:
| Project | Compiler | Sources | Artifacts | Cold Compile | jvmcache Hit | Speedup |
|---|---|---|---|---|---|---|
| Ajalt Clikt | kotlinc 2.4 |
61 .kt |
241 .class/.module |
23,117.5 ms | 30.5 ms | 756.9x |
| Apache Commons Lang | javac 21 |
264 .java |
394 .class |
7,478.9 ms | 63.1 ms | 118.5x |
| Apache Commons IO | javac 21 |
277 .java |
372 .class |
3,917.2 ms | 104.7 ms | 37.4x |
| Square JavaPoet | javac 21 |
17 .java |
35 .class |
1,380.1 ms | 6.2 ms | 221.8x |
| AOSP Soong Javac | javac 21 |
multi-file | $outDir + $annoDir |
546.3 ms | 2.6 ms | 208.7x |
| AOSP Soong Kotlinc | kotlinc 21 |
multi-file | classes + headers | 4,738.1 ms | 2.8 ms | 1669.1x |
Bytecode Fidelity: 100% bit-for-bit identical SHA-256 tree matches verified across all runs.
- Broad Compiler Support: Transparent drop-in support for
javac,kotlinc,kapt(Kotlin Annotation Processing),d8(Android Dexer), andr8(Android Optimizer / Shrinker). - Persistent In-Process JVM Daemon: Background worker daemon communicating over Unix Domain Sockets (
StandardProtocolFamily.UNIX) with thread pooling, completely avoiding repeated JVM bootstrap startup penalties. - Surgical Delta Compilation: When only a subset of files change in a large target,
jvmcachecompiles only the modified files and atomically merges them with baseline cached class outputs. - Two-Level CAS Storage & Inode Deduplication: Centralized Content-Addressable Storage (CAS) with SHA-256 blob deduplication. Identical
.classfiles across different modules or targets share the exact same underlying disk inode via hardlinks. - AppCDS Class Data Sharing Acceleration: Automatically generates and loads JVM Application Class Data Sharing archives (
cds.rs) for sub-second startup when running standalone compiler processes. - Strict ABI Caching: Optional ABI-based hashing (
JVMCACHE_STRICT_ABI=1withjvm-abi-gen) that prevents rebuilding downstream consumers when internal implementation details change without affecting public API contracts. - Fail-Safe Passthrough: If cache storage encounters any I/O errors, read-only permissions, or disk limits,
jvmcachetransparently falls back to direct compiler execution without failing the build. - Sandboxed Build & Container Parity: Implements
jvmcache -k cache_dir, matchingccache's contract for container and sandbox bind mounting (e.g., AOSPnsjailand Docker). - Dynamic Portability: Zero hardcoded machine paths. Automatically resolves project roots, standard toolchains, and AOSP hermetic prebuilts.
- Bytecode Determinism Safety: Preserves left-to-right classpath precedence, tracks anonymous inner class numbering, handles
--releasebytecode targets, and captures multi-directory outputs (-d,-s,-h). - Compiler Fingerprint Memoization: Avoids the multi-second startup penalty of querying
kotlinc -versionvia inode/mtime stat memoization.
Use the automated atomic rebuild and deployment wrapper:
./deploy.sh # Rebuild release binary and atomically refresh bin/
./deploy.sh --test # Rebuild, run all verification test suites, and redeploy
./deploy.sh --install # Rebuild and atomically install to ~/.local/binOr build manually with Cargo:
cargo build --releaseThe compiled native binary is located at target/release/jvmcache.
Prepend bin/ to $PATH, or deploy to ~/.local/bin:
# Using project symlinks:
export PATH="/path/to/jvmcache/bin:$PATH"
# Or install to user directory:
./deploy.sh --install
export PATH="$HOME/.local/bin:$PATH"Any build tool invoking javac, kotlinc, kapt, d8, or r8 will now automatically route through jvmcache.
jvmcache integrates directly with AOSP toolchain overrides:
export ALTERNATE_JAVAC=/path/to/jvmcache/bin/javac
export ALTERNATE_KOTLINC=/path/to/jvmcache/bin/kotlinc
export ALTERNATE_D8=/path/to/jvmcache/bin/d8
export ALTERNATE_R8=/path/to/jvmcache/bin/r8In pom.xml, configure maven-compiler-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<fork>true</fork>
<executable>/path/to/jvmcache/bin/javac</executable>
</configuration>
</plugin>In build.gradle:
tasks.withType(JavaCompile).configureEach {
options.fork = true
options.forkOptions.executable = '/path/to/jvmcache/bin/javac'
}# View cache statistics, hit rate, and storage summary
jvmcache --show-stats # or -s
# View recent compilation and caching activity log
jvmcache --log # or -l
# Tail the last N entries of the activity log (default: 25)
jvmcache --tail 50 # or -t 50
# Inspect cached artifacts/manifests matching a filter
jvmcache --objects # or -o <filter>
# Clear the activity log
jvmcache --clear-log
# View active resolved configuration and detected compiler paths
jvmcache --show-config # or -p
# Query specific configuration value (e.g. for build scripts)
jvmcache -k cache_dir
jvmcache -k max_size
# Clear all cached objects and reset statistics
jvmcache --clear # or -Cjvmcache resolves configuration in the following precedence order:
-
Environment Variables:
JVMCACHE_DIR: Cache storage directory (default:~/.cache/jvmcache).JVMCACHE_CONFIG: Custom configuration file path.JVMCACHE_MAXSIZE: Maximum cache size in MB (default:5120).JVMCACHE_JAVAC: Explicit override for the realjavacbinary.JVMCACHE_KOTLINC: Explicit override for the realkotlincbinary.JVMCACHE_KAPT: Explicit override for the realkaptbinary.JVMCACHE_D8: Explicit override for the reald8binary.JVMCACHE_R8: Explicit override for the realr8binary.JVMCACHE_HARDLINK: Enable hardlink artifact restoration (1or0, default:1).JVMCACHE_DAEMON: Enable persistent JVM worker daemon (1or0, default:1).JVMCACHE_AUTO_SPAWN: Automatically spawn daemon worker on demand (1or0, default:1).JVMCACHE_CDS: Enable AppCDS shared archive acceleration (1or0, default:1).JVMCACHE_AUTO_FLAGS: Enable automated compiler flag optimizations (1or0, default:1).JVMCACHE_STRICT_ABI: Enforce strict ABI hashing whenjvm-abi-genis present (1or0, default:0).JVMCACHE_KOTLINC_THREADS: Thread count for kotlinc parallel bytecode generation (default: logical CPU cores).JVMCACHE_VERBOSE: Enable verbose debug logging (1or0, default:0).
-
Project Configuration:
.jvmcache.jsonor.jvmcache/config.jsonin the current working directory or any parent directory. -
User Configuration:
${XDG_CONFIG_HOME}/jvmcache/config.jsonor~/.config/jvmcache/config.json. -
Defaults: Portable user cache directory.
For an in-depth first-principles analysis comparing native C/C++ compilation (ccache) to JVM compilation models, bytecode determinism proofs, and full technical specifications, see RESEARCH_AND_SPECIFICATION.md.
Licensed under the Apache License, Version 2.0. See LICENSE for details.