Java Gradle内置Docker容器占用太多内存

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 构建最近开始失败,因为它们占用了太多内存,其中一个进程被主机杀死,我可以通过

我需要你的帮助来限制Gradle构建在构建机器上占用的内存量。我尝试构建一个Android项目,它有将近100个模块,包括一个
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以限制内存使用,但失败了。我尝试了以下各种设置组合:

  • 我发现JVM不知道Docker内存限制,它需要
    -XX:+UnlockExperimentalVMOptions-XX:+UseCGroupMemoryLimitForHeap
    ,所以我添加了它并删除了
    Xmx4g
    。没有帮助。使用
    Xmx4g
    几乎是一样的
  • 我找到了
    -XX:MaxRAMFraction
    ,但我觉得变化不大
  • 我尝试了
    Xmx2g
    ,但由于抛出
    OutOfMemoryError:GC开销限制在某个点上超过了
    ,构建失败
  • 我尝试了
    -XX:MaxPermSize=1g-XX:MaxMetaspaceSize=1g
    ,它挂起了构建并抛出了
    OutOfMemoryError:Metaspace
    ,因此我将它们增加到
    2g
    ,我认为这并没有限制总体内存使用
  • 我试着把工人人数限制在4人和1人之间
  • 我发现Kotlin编译器可以使用不同的执行策略:
    -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守护进程和Gradle CLI感到困惑,所以我尝试了一些不同的组合(但不是所有可能的组合,这样我就很容易错过了一些东西)
    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