Docker 容器中的 Gradle 构建占用了太多内存
我需要你的帮助来限制Gradle构建在构建机器上占用的内存量。我试图构建一个包含近100个模块的Android项目,其中包括一个模块和许多.单个 Gradle 命令同时执行构建、lint 和测试(如果这很重要,则包括 Robolectric 测试)。com.android.application
com.android.library
我在一个基于 jetbrains/teamcity-agent 的 Docker 容器中运行构建。容器被限制为仅使用 64GB 主机 RAM 中的 10GB 使用选项。mem_limit
构建最近开始失败,因为它们占用了太多的内存,其中一个进程被主机杀死,我可以通过在主机上运行来看到。它可能看起来像这样:dmesg
[3377661.066812] Task in /docker/3e5e65a5f99a27f99c234e2c3a4056d39ef33f1ee52c55c4fde42ce2f203942f killed as a result of limit of /docker/3e5e65a5f99a27f99c234e2c3a4056d39ef33f1ee52c55c4fde42ce2f203942f
[3377661.066816] memory: usage 10485760kB, limit 10485760kB, failcnt 334601998
[3377661.066817] memory+swap: usage 0kB, limit 9007199254740988kB, failcnt 0
[3377661.066818] kmem: usage 80668kB, limit 9007199254740988kB, failcnt 0
[3377661.066818] Memory cgroup stats for /docker/3e5e65a5f99a27f99c234e2c3a4056d39ef33f1ee52c55c4fde42ce2f203942f: cache:804KB rss:10404288KB rss_huge:0KB shmem:0KB mapped_file:52KB dirty:12KB writeback:0KB inactive_anon:1044356KB active_anon:9359932KB inactive_file:348KB active_file:72KB unevictable:0KB
[3377661.066826] [ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name
[3377661.066919] [ 6406] 0 6406 5012 14 81920 74 0 run-agent.sh
[3377661.066930] [ 8562] 0 8562 569140 2449 319488 6762 0 java
[3377661.066931] [ 8564] 0 8564 1553 20 53248 7 0 tail
[3377661.066936] [ 9342] 0 9342 2100361 92901 2437120 36027 0 java
[3377661.067178] [31134] 0 31134 1157 17 57344 0 0 sh
[3377661.067179] [31135] 0 31135 5012 83 77824 0 0 bash
[3377661.067181] [31145] 0 31145 1233001 21887 499712 0 0 java
[3377661.067182] [31343] 0 31343 4356656 2412172 23494656 0 0 java
[3377661.067195] [13020] 0 13020 56689 39918 413696 0 0 aapt2
[3377661.067202] [32227] 0 32227 1709308 30383 565248 0 0 java
[3377661.067226] Memory cgroup out of memory: Kill process 31343 (java) score 842 or sacrifice child
[3377661.067240] Killed process 13020 (aapt2) total-vm:226756kB, anon-rss:159668kB, file-rss:4kB, shmem-rss:0kB
我正在观察某些场景中的内存使用情况,我注意到单个进程(Gradle守护程序)正在慢慢占用超过8GB,所以它比我预期的要多。top
java
gradle.properties
org.gradle.jvmargs=-Xmx4g
我尝试了几种方法来配置Gradle以以某种方式限制内存使用,但我失败了。我尝试了以下设置是各种组合:
- 我发现JVM不知道Docker内存限制,它需要,所以我添加并删除了它。没有帮助。使用几乎是一样的。
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
Xmx4g
Xmx4g
- 我找到了,但我认为它没有太大变化。
-XX:MaxRAMFraction
- 我试过了,但它在某个时候投掷失败了。
Xmx2g
OutOfMemoryError: GC overhead limit exceeded
- 我尝试了哪个挂起了构建并抛出,所以我增加了它们,我认为这不会限制整体内存使用量。
-XX:MaxPermSize=1g -XX:MaxMetaspaceSize=1g
OutOfMemoryError: Metaspace
2g
- 我尝试将工人人数限制为4和1。
- 我发现 Kotlin 编译器可以使用不同的执行策略:.我想它可能会有所帮助,因为内存消耗的进程较少,但守护进程仍然占用超过8GB。
-Dkotlin.compiler.execution.strategy="in-process"
- 使用 set to 似乎稍微限制了内存(守护程序占用了大约 4.5GB,所以看起来很有前途),但它只是挂起了 构建 。然后我会尝试另一个分数。我想4是默认值,对吧?
GRADLE_OPTS
-Dorg.gradle.jvmargs="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=10" -Dkotlin.compiler.execution.strategy="in-process"
Expiring Daemon because JVM heap space is exhausted
我也对如何将参数传递到Gradle守护进程与Gradle CLI感到困惑,所以我尝试了两者的不同组合(但不是每个可能的组合,所以我很容易错过一些东西),以及内部。能够以某种方式打印守护程序使用的实际 JVM 参数会很有帮助。我试图弄清楚的唯一方法是使用和检查传递给进程的参数。gradle.properties
JAVA_OPTS
GRADLE_OPTS
org.gradle.jvmargs
ps -x
java
我可能应该提到我使用选项和Gradle 6.2.2尝试了所有这些东西。我现在正在试用Gradle 6.3,但我不指望它有帮助。--no-daemon
如果我在具有16GB RAM的MacBook上使用Android Studio或Gradle命令在本地运行构建版本,则由于内存限制问题,它永远不会失败。此问题仅在生成服务器上发生。
我不知道接下来该怎么做来限制构建过程使用的内存量。我唯一没有尝试过的想法是:
- 在 Gradle 任务中设置限制,例如 .这会有帮助吗?
tasks.withType(JavaCompile) { ... }
- 删除我使用的不太相关的Gradle插件,例如
com.autonomousapps.dependency-analysis
不幸的是,所有测试都非常耗时,因为根据条件,单个构建可能需要长达30-60分钟才能执行,因此我想避免盲目测试它。
我是不是做错了?是否有任何其他选项来限制内存?有没有办法分析占用这么多内存的东西?是否可以在构建过程中强制使用 GC?我应该问一个不同的问题吗?