【问题标题】:How to work around gradle being broken in docker environments?如何解决 docker 环境中 gradle 被破坏的问题?
【发布时间】:2021-03-05 15:33:59
【问题描述】:

Gradle 在 docker 环境下无法正常工作,注定会占用过多的内存而被杀掉。

内存管理器使用以下类获取其快照

https://github.com/gradle/gradle/blob/master/subprojects/process-services/src/main/java/org/gradle/process/internal/health/memory/MemInfoOsMemoryInfo.java

尤其是 Gradle 通过读取 /proc/meminfo 来确定剩余多少可用内存,这会在容器中提供不准确的读取。

Gradle 仅在收到请求以创建具有更大最小堆大小的新 Worker Daemon 时才会杀死 Worker Daemons,然后根据此读数可用。

因此,Gradle 将继续制造工人,直到它用完容器的分配数量并被杀死。

有人对此有解决方法吗?真的不明白这对更多人来说如何不是问题。我想只有当你的工作守护进程不能被重用并创建新的守护进程时才会真正成为一个问题,这对我来说就是这种情况,因为我有大量的模块。

我有一个临时的解决方法,我给每个 jvm 生成一个巨大的 -Xms,所以它总是触发最小堆大小 > 可用,所以总是删除以前的工作守护进程,但这并不令人满意。

--编辑

为了抢占某些东西,--max-workers 不会影响允许存在的 Worker Daemon 的数量,它只会影响允许处于活动状态的数量。即使使用--max-workers = 1,也允许任意多个空闲的Worker Daemon。

【问题讨论】:

  • 问题是 Gradle 使用了太多内存,它产生了太多守护进程,还是它没有看到比它想象的更多的可用内存?无论如何,您是否考虑过使用--no-daemon 关闭守护进程?您还确定所有模块都需要不同的 JVM 设置来构建吗?如果你可以对齐它们,Gradle 将不会产生多个守护进程。
  • @BjørnVester 问题是它使用了太多的内存,这是由于产生了太多的守护进程而没有杀死旧的守护进程,这是由于错误地确定了剩余多少可用内存。我有 --no-daemon ,但这只会影响“主”守护进程,即协调一切的守护进程。即使使用 --no-daemon ,你仍然会得到许多工作守护进程。关于我的所有模块是否需要不同的 JVM 设置,我不确定,但 Gradle 用来确定现有守护进程是否兼容的一件事是它的类加载器层次结构。

标签: docker jenkins gradle


【解决方案1】:

编辑 - 忽略下面的,它有点工作,但我已经通过覆盖 MemInfoOsMemoryInfo 类修补了 Gradle,它工作得更好。很快将提供一个指向 MR 到 Gradle 的链接。

找到一个合理的解决方法,我们侦听操作系统内存更新,每次任务完成时,我们都会请求比确定可用内存更多的内存,以确保停止守护进程。

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
            }
        })
    }
}

【讨论】:

  • 感谢您的建议,不幸的是对我来说它不起作用。 gradle 守护进程仍然几乎总是消失。我同意你的观点,这很奇怪,没有得到更多的关注。也许你可以在你的问题中编辑,这个问题只有在你限制容器的内存时才会出现。
  • @user1259201 它对我来说也不是很完美。从那以后,我分叉了 Gradle 并编写了一个运行良好的补丁!一旦我在 gradle 上做了一个 MR,我会提供一个链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多