避免和调试Java Memory错误

如何在Circleci上避免和调试Java Memory错误。

概要

Java虚拟机(JVM)为基于Java的应用程序提供了便携式执行环境。没有任何内存限制,JVM预先分配了系统中可用的总内存的一小部分。Circleci在大型机器上运行基于容器的构建,许多内存。每个容器的内存限制比机器上可用的总量较小。

默认情况下,Java的配置是这样的,它将使用:

  • 超过1/64您的总内存(对于带4Gib的船坞介质,这将是64 MIB)
  • 少于1/4你的总内存(对于有4GiB RAM的Docker媒体,这将是1GiB)。

6月3日2020年使用Docker Executor时,这些限制是可见的。这意味着最近的Java版本将正确检测作业可用的CPU数和RAM的数量。

对于旧版本的Java,这可能导致JVM看到大量内存和CPU可用于它,并尝试使用的多于分配给容器。此预配置可以产生内存(OOM)错误,这难以调试,因为错误消息缺乏细节。通常你会看到一个137.退出代码,这意味着进程已经完成Sigkill.由oom杀手怂恿(137 = 128 +“杀死-9”)。

您可以看到您的容器分配多少内存,并通过查看以下文件,以及使用多少。

/ sys / fs / cgroup /内存/内存。limit_in_bytes / sys / fs / cgroup /内存/ memory.max_usage_in_bytes

UseContainersupport.

Java的最新版本(JDK 8u191和JDK 10及以上)包括一个标志UseContainersupport.违约。这个标志使JVM能够使用容器可用的CGroup内存约束,而不是机器上更大的内存。在Docker和其他容器运行时下,这将让JVM更准确地检测内存约束,并在这些约束内设置默认内存使用情况。你可以使用MaxRAMPercentage标志以定制使用的可用RAM的分数,例如,-xx:maxrampercentage = 90.0

手动记忆限制

即使有cgroup支持,JVM仍然可以使用太多的内存,例如,如果它执行一个工作进程池。为了防止JVM预分配太多内存,需要声明内存限制使用Java环境变量。调试OOM错误,查找适当的退出代码

使用Java环境变量设置内存限制

您可以设置几个Java环境变量来管理JVM内存使用。这些变量具有相似的名称,并且以复杂的方式相互作用。

下表显示了这些环境变量,以及它们在使用不同构建工具时的优先级级别。数字越低,优先级越高,0是最高的。

Java环境变量 java. Maven 芬兰湾的科特林 莱茵
_JAVA_OPTIONS 0. 0. 0. 0. 0.
java_tool_options. 2 3. 2 2 2
JAVA_OPTS 没有 2 没有 1 没有
JVM_OPTS. * 没有 没有 没有 *
Lein_JVM_OPTS. 没有 没有 没有 没有 1
Gradle_opts. 没有 1 没有 没有 没有
MAVEN_OPTS 没有 没有 1 没有 没有
CLI arg游戏 1 没有 没有 没有 没有

下面列出了上述环境变量,并详细说明了为什么要选择这些环境变量。

_JAVA_OPTIONS

此环境变量优先于所有其他环境变量。JVM直接读取它并覆盖所有其他Java环境变量,包括命令行参数。由于这种能力,可以考虑使用更特定的Java环境变量。

注意:_JAVA_OPTIONS是Oracle独家。如果您使用的是使用不同的运行时,请确保检查此变量的名称。例如,如果您使用的是IBM Java运行时,则将使用IBM_Java_Options.

java_tool_options.

这个环境变量是一个安全的选择用于设置Java内存限制。java_tool_options.可以被所有Java虚拟机读取,您可以用命令行参数或更特定的环境变量轻松地覆盖它。

JAVA_OPTS

JVM不读取该环境变量。相反,一些基于java的工具和语言使用它来将内存限制传递给JVM。

JVM_OPTS.

这个环境变量是Clojure的独家。莱茵用途JVM_OPTS.将内存限制传递给JVM。

注意:JVM_OPTS.不会影响难忘莱茵它也不能直接将内存限制传递给Java。影响莱茵的可用内存,使用Lein_JVM_OPTS.。直接将内存限制转到Java,使用_JAVA_OPTIONS要么java_tool_options.

Lein_JVM_OPTS.

这个环境变量是独家的莱茵

Gradle_opts.

查看Gradle文档内存设置

这个环境变量是Gradle项目专有的。使用它来覆盖设置的内存限制java_tool_options.

MAVEN_OPTS

请参阅Maven文档内存设置

此环境变量是Apache Maven项目的独家。使用它来覆盖设置的内存限制java_tool_options.

调试Java OOM错误

不幸的是,调试Java OOM错误通常会归结为查找退出代码137.在错误输出中。

确保你的- xx: MaxRAMPercentage = NN要么-xmx = nn.大小足够大,可以完全构建应用程序,同时又足够小,可以让其他进程共享CircleCI构建容器的剩余内存。

即使JVM的最大堆大小大于作业的限制,垃圾收集器也可以跟上分配速率,并避免使用太多内存并被杀死的过程。分配给垃圾收集器的默认线程数基于可用CPU的数量,因此CGROUP可见性变化在2020年6月3日进行的操作可能会导致您的应用程序比以前消耗更多的内存,从而导致OOM死亡。解决这个问题的最佳方法是在作业的可用RAM中配置最大堆大小,这将导致尽快触发完整的GC,以避免违反任何限制。

如果您仍然持续击中内存限制,请考虑增加工作的RAM分配

也可以看看

Java语言指南Android教程