Passing ziptime-info=false to ZipFileSystemProvider (along with other classpath performance ideas)

Jason Zaugg jzaugg at gmail.com
Sun Mar 2 13:43:14 UTC 2025


I've been analysing the performance of javac in a relatively large codebase
and found classpath scanning to be the dominant factor. There are large
numbers of compilation tasks, most with long classpaths including large
JARs.

I've been using the wall-time profiling mode of async-profiler to analyse
where time is being spent.

I've been able improve build times (most dramatically on Windows, 750s
reduced to 350s) by modifying javac to:

1. pass ziptime-info=false to the env Map of jarFsProvider.newFileSystem,
which means the classpath scan in the constructor of ArchiveContainer need
only read the ZIP central directory, rather then reading per-entry Extended
Time metadata.
2. Extend cache lifetime for FSInfo.getJarClassPath
3. share ZipFileSystem instances across compilation tasks in a build
session (multiple JavacTasks). The (custom) build tool knows which JARs are
immutable.

I don't see any supported way to make this change via the public compiler
APIs, so I'm currently using a bytecode transform to patch the
implementation [1].

Change 1 is self contained and low risk -- would this be worth a patch?
Other calls to newFilesystem, e.g in inferModuleName, should also be
changed to for consistency.

Change 2 would not be needed if I could share a CacheFSInfo instance across
a number of compilation tasks, but I don't see a way to do this via the
public APIs. Am I missing something here?

Change 3 doesn't seem to belong in javac, but perhaps could be accommodated
with an extension point akin to StandardFileManager.setPathFactory. Two
options:

// option a), a wrapper around ZipFileSystemProvider can defer javac's
close() calls
void setJarFsProvider(FileSystemProvider provider)

// option b)
void setJarFileSystemFactory(JarFileSystemFactory factory)
interface JarFileSystemFactory {
   FileSystem newFileSystem(FileSystemProvider provider, Path path,
Map<String, String> env)
   void close(FileSystem fileSystem)
}

I reviewed the Java integration in other build tools to see if this problem
has been tackled elsewhere. Bazel and Gradle do use the non-public compiler
API but don't appear to add this sort of caching.

Regards,

Jason Zaugg


[1] https://github.com/retronym/jarcache
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20250302/f8fc594b/attachment-0001.htm>


More information about the compiler-dev mailing list