避免和调试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分配。