Java Gradle内置Docker容器占用太多内存
我需要你的帮助来限制Gradle构建在构建机器上占用的内存量。我尝试构建一个Android项目,它有将近100个模块,包括一个Java Gradle内置Docker容器占用太多内存,java,android,docker,kotlin,gradle,Java,Android,Docker,Kotlin,Gradle,我需要你的帮助来限制Gradle构建在构建机器上占用的内存量。我尝试构建一个Android项目,它有将近100个模块,包括一个com.Android.application模块和许多com.Android.library。单个Gradle命令同时执行构建、lint和测试(如果有必要,还包括机器人分子测试) 我在基于的Docker容器中运行构建。使用mem\u limit选项,容器仅限于使用64GB主机RAM中的10GB 构建最近开始失败,因为它们占用了太多内存,其中一个进程被主机杀死,我可以通过
com.Android.application
模块和许多com.Android.library
。单个Gradle命令同时执行构建、lint和测试(如果有必要,还包括机器人分子测试)
我在基于的Docker容器中运行构建。使用mem\u limit
选项,容器仅限于使用64GB主机RAM中的10GB
构建最近开始失败,因为它们占用了太多内存,其中一个进程被主机杀死,我可以通过在主机上运行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
我使用top
观察了某些场景中的内存使用情况,我注意到单个java
进程(Gradle守护进程)正在慢慢占用超过8GB的内存,而Gradle.properties
拥有org.Gradle.jvmargs=-Xmx4g
,所以这比我预期的要多得多
我尝试了几种方法来配置Gradle以限制内存使用,但失败了。我尝试了以下各种设置组合:
-XX:+UnlockExperimentalVMOptions-XX:+UseCGroupMemoryLimitForHeap
,所以我添加了它并删除了Xmx4g
。没有帮助。使用Xmx4g
几乎是一样的-XX:MaxRAMFraction
,但我觉得变化不大Xmx2g
,但由于抛出OutOfMemoryError:GC开销限制在某个点上超过了
,构建失败-XX:MaxPermSize=1g-XX:MaxMetaspaceSize=1g
,它挂起了构建并抛出了OutOfMemoryError:Metaspace
,因此我将它们增加到2g
,我认为这并没有限制总体内存使用-Dkotlin.compiler.execution.strategy=“in-process”
。我想这可能有点帮助,因为占用内存的进程更少,但守护进程仍然占用了超过8GB的内存GRADLE\u OPTS
设置为-Dorg.GRADLE.jvmargs=“-XX:+UnlockExperimentalVMOptions-XX:+UseCGroupMemoryLimitForHeap-XX:MaxRAMFraction=10”-Dkotlin.compiler.execution.strategy=“in-process”
似乎限制了一些内存(守护进程占用了大约4.5GB,因此看起来很有希望)但由于JVM堆空间耗尽,它只是挂起了带有过期守护进程的构建。那我再试试另一个分数。我想默认值是4,对吗Gradle.properties
、JAVA_OPTS
和Gradle_OPTS
以及org.Gradle.jvmargs
内部的组合。能够以某种方式打印守护进程使用的实际JVM参数会很有帮助。我试图找出它的唯一方法是使用ps-x
并检查传递给java
进程的参数
我应该提到的是,我使用——无守护进程选项和Gradle 6.2.2尝试了所有这些东西。我现在正在试用Gradle 6.3,但我不希望它有帮助
如果我在带有16GB内存的MacBook上使用Android Studio或Gradle命令在本地运行构建,它永远不会因为内存限制问题而失败。此问题仅在生成服务器上发生
我不知道接下来要做什么来限制构建过程所使用的内存量。我唯一没有尝试过的剩余想法是:
在Gradle任务中设置限制,例如像tasks.withType(JavaCompile){…}
。那会有帮助吗
删除我使用的不太相关的Gradle插件,例如com.autonomousapps.dependency analysis
不幸的是,所有的测试都非常耗时,因为单个构建可能需要30-60分钟才能执行,这取决于条件,所以我希望避免盲目测试
我做错了吗?是否有其他限制内存的选项?有没有办法分析什么东西占用了这么多内存?是否可以在构建过程中强制GC?我应该问另一个问题吗?接收操作系统内存更新,并在每次任务完成时请求比确认可用的内存更多的内存,以便守护进程停止
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
}
})
}
}
嗨@Andrzej,你找到解决方法了吗?没有,我没有,不幸的是我有同样的问题,如果我找到解决方案,我会更新你的Q:D