Gradle缓存为什么会多次包含依赖项?

4
我们通过Gitlab Pipeline Jobs将Gradle缓存作为ZIP上传到S3。解压其中一个ZIP文件(其中只包含.gradle文件夹)显示许多依赖项以相同的版本多次出现:1x在jars-9和1x在modules-2中: enter image description here 为什么会发生这种情况,如何避免?由于此原因,我们的CI缓存比实际需要的大20-30%,尤其是对于像Kotlin编译器这样的大型依赖项: enter image description here JAR之间的大小差异可以归因于JAR文件压缩开启或关闭,它们在内容上是相同的。

官方解释关于.gradle文件夹结构的说明并没有帮助。

1个回答

4

Gradle的依赖缓存旨在提高效率和可靠性。 它包括两种主要的存储类型:

  1. 基于文件的下载工件存储,包括二进制文件(如jar文件)和原始下载元数据(如POM和Ivy文件)。 下载工件的存储路径包括SHA1校验和,这意味着具有相同名称但内容不同的两个工件可以轻松缓存($GRADLE_USER_HOME/caches)。

  2. 已解析的模块元数据的二进制存储,包括解析动态版本、模块描述符和工件的结果。

你在Gradle缓存中看到的jars-*modules-2目录与这两种不同类型的存储相关。

jars-*目录可能是指基于文件的下载工件存储。 存储在此目录中的每个工件在其存储路径中都包括SHA1校验和。 这种设计允许Gradle缓存具有相同名称但内容不同的两个工件,并确保如果具有相同SHA1校验和的工件已经存在于缓存中,则不会多次下载相同的工件。

modules-2 目录则是指已解析模块元数据的二进制存储区。该目录以二进制格式保存了依赖项解析的各个方面的记录,包括将动态版本解析为具体版本的结果、特定模块的已解析模块元数据以及特定构件的已解析构件元数据。

这两个目录之间是不同的,因为它们提供了不同的功能并存储不同类型的数据。

Gradle architecture

如之前与Vampire评论区中讨论的,我添加了以下内容:

当Gradle解析依赖项时,它会下载依赖项的JAR文件并将其存储在modules-2目录中。

如果对依赖项应用类路径转换,则转换的结果(如果使用身份转换,则可能与原始结果相同)会存储在jars-*目录中。这使得Gradle可以缓存转换的结果,避免将来使用相同的转换和相同的依赖项时再次执行转换。

这就解释了为什么内容完全相同。


在减小CI缓存大小方面,由于Gradle缓存的工作方式,不同缓存目录中相同依赖项的多个实例可能是无法避免的。

但是,您可以配置CI/CD管道以仅缓存必要的目录或文件,或使用增量构建等技术来最小化需要缓存的数据量。
您还可以考虑定期手动或编程方式清理Gradle缓存,以删除未使用或过时的文件。


你的解释带有假设,与OP已经得出的结论相矛盾。他说这些文件都是具有相同内容的jar文件,大小差异只是因为不同的压缩率。 - Vampire
@Vampire 我同意。我仍然不清楚为什么相同的JAR文件在缓存中可能具有不同的大小。 - VonC
完全不知道且没有调查的情况下,仅仅根据发帖者所说,我猜测module-2中的文件与下载的完全一样,而在jars-9中则是未压缩的重复存储,这样可以更快地访问其内容,因为您无需解压它。只是一个大胆的猜测。 - Vampire
从一个粗略的观察来看,jars-9 包含了类路径转换的结果。例如,用于检测配置缓存输入的仪器化。也有一些情况下会进行身份转换,但我没有进一步研究为什么会这样,以及是否有任何意义。 - Vampire
就像我之前说的那样,只是一个粗略的了解。也许只针对buildscript依赖项进行检查,这是指仪器化或类似的内容。 - Vampire
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接