迭代org.springframework.boot.loader.jar.JarFile#entries()
非常慢。对JarFileEntries#getEntry
by 的连续调用EntryIterator#next
导致底层RandomAccessFile
来回跳转,以便从 jar 文件的中央目录重新读取文件头。如果JarFileEntries#visitFileHeader
存储完整的内容FileHeader
而不仅仅是它的偏移量和名称的哈希值,这可能会快得多。
在使用https://github.com/joinfaces/joinfaces/pull/565时,我注意到扫描重新打包的 Spring Boot 应用程序时,ClassGraph 比扫描未打包形式的同一应用程序要慢 500 毫秒。所以我查看了 ClassGraph 的代码,发现它提取了所有嵌套的 jar 以便扫描它们。为了提高扫描嵌套 jar 的性能,我准备了以下补丁来使用 JarFile 实现,spring-boot-loader
以避免提取所有嵌套 jar 的额外成本:
https://github.com/larsgrefer/classgraph/compare/ba4c69347eaf915571e9f5142e09f7a481471570 ...cfb317aff4d6949afbddcc1fd0ad78b118ef52ec?expand=1
令人惊讶的是,这种方法甚至有点慢,所以我更深入地研究了代码,并将性能差异追溯到此处完成的迭代:https: //github.com/classgraph/classgraph/blob/b170d2bebb871824f7d53d54aa7a9b6939f25cf0/src/main/java/ io/github/classgraph/utils/JarfileMetadataReader.java#L148
在我的测试中,迭代org.springframework.boot.loader.jar.JarFile
a 比迭代 a 慢大约 5 到 10 倍java.util.zip.ZipFile
。这种性能影响是如此严重,以至于首先提取嵌套 jar 的速度更快,以便能够使用java.util.zip.ZipFile
在我阅读了https://github.com/spring-projects/spring-boot/commit/e2368b909b46bc5bcec6792fb208ba9bd0fe6aaa的提交消息后,在我看来,内存效率对你来说比迭代性能更重要。所以我的问题是,您是否愿意接受更改当前行为的拉取请求或允许 ClassGraph 更改实现的行为JarFileEntries
以及此 PR 的外观。