And*_*ost 20 java android gradle kotlin docker
我需要你的帮助来限制 Gradle 构建在构建机器上占用的内存量。我尝试构建一个包含近 100 个模块的 Android 项目,其中包括一个com.android.application模块和许多com.android.library. 单个 Gradle 命令同时执行构建、lint 和测试(如果重要的话,还包括 Robolectric 测试)。
我在基于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
Run Code Online (Sandbox Code Playgroud)
我用的是观察某些情况下的内存使用情况top,我注意到一个单一的java过程(在摇篮守护进程),同时慢慢占据了8GBgradle.properties不得不org.gradle.jvmargs=-Xmx4g因此它的方式太多了,比我期望的那样。
我尝试了几种方法来配置 Gradle 以某种方式限制内存使用,但我失败了。我尝试了以下设置是各种组合:
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap所以我添加了它并删除了Xmx4g. 没有帮助。使用Xmx4g几乎相同。-XX:MaxRAMFraction但我认为它没有太大变化。Xmx2g但它OutOfMemoryError: GC overhead limit exceeded在某个时候抛出失败了。-XX:MaxPermSize=1g -XX:MaxMetaspaceSize=1g将构建挂起并抛出,OutOfMemoryError: Metaspace所以我将它们增加到2g不限制整体内存使用量的程度,我认为。-Dkotlin.compiler.execution.strategy="in-process". 我想这会有所帮助,因为消耗内存的进程较少,但守护进程仍占用超过 8GB 的空间。GRADLE_OPTSset to-Dorg.gradle.jvmargs="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=10" -Dkotlin.compiler.execution.strategy="in-process"似乎稍微限制了内存(守护进程占用了大约 4.5GB,所以它看起来很有希望)但它只是用Expiring Daemon because JVM heap space is exhausted. 然后我会尝试另一个分数。我想 4 是默认值,对吧?我也搞不清楚的参数是如何传递到摇篮守护VS摇篮CLI所以我尝试了一些不同的组合(但不是每一个可能的组合,所以我可以很容易错过的东西)两者gradle.properties,JAVA_OPTS并GRADLE_OPTS与org.gradle.jvmargs里面。能够以某种方式打印守护程序使用的实际 JVM 参数会很有帮助。我试图弄清楚的唯一方法是使用ps -x和检查传递给java进程的参数。
我应该提到我使用--no-daemonoption 和 Gradle 6.2.2尝试了所有这些东西。我现在正在试用 Gradle 6.3,但我不希望它有帮助。
如果我在具有 16GB RAM 的 MacBook 上使用 Android Studio 或 Gradle 命令在本地运行构建,它永远不会因内存限制问题而失败。此问题仅发生在构建服务器上。
我不知道接下来要做什么来限制构建过程使用的内存量。我还没有尝试过的唯一剩下的想法是:
tasks.withType(JavaCompile) { ... }. 那会有帮助吗?com.autonomousapps.dependency-analysis不幸的是,所有测试都非常耗时,因为根据条件,单个构建可能需要长达 30-60 分钟的时间来执行,所以我想避免盲目测试。
我做错了吗?还有其他选项可以限制内存吗?有没有办法分析一下是什么占用了这么多内存?是否可以在构建过程中强制 GC?我应该问一个不同的问题吗?
小智 1
接收操作系统内存更新,并在每次任务完成时请求比确认可用的内存更多的内存,以便守护进程停止。
import org.gradle.process.internal.health.memory.OsMemoryStatus
import org.gradle.process.internal.health.memory.OsMemoryStatusListener
import org.gradle.process.internal.health.memory.MemoryManagertask
task expireWorkers {
doFirst {
long freeMemory = 0
def memoryManager = services.get(MemoryManager.class)
gradle.addListener(new TaskExecutionListener() {
void beforeExecute(Task task) {
}
void afterExecute(Task task, TaskState state) {
println "Freeing up memory"
memoryManager.requestFreeMemory(freeMemory * 2)
}
})
memoryManager.addListener(new OsMemoryStatusListener() {
void onOsMemoryStatus(OsMemoryStatus osMemoryStatus) {
freeMemory = osMemoryStatus.freePhysicalMemory
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1254 次 |
| 最近记录: |