"Insufficient memory" 在 Jenkins 服务器启动时

"Insufficient memory" on Jenkins server startup

这里是 Jenkins 的第一次用户,开始使用时遇到了一些麻烦。从 Linux shell 我 运行 一个命令,如:

java -Xms512m -Xmx512m -jar jenkins.war

并不断收到如下错误:

# There is insufficient memory for the Java Runtime Environment to continue.
# pthread_getattr_np
# An error report file with more information is saved as:
# /home/twilliams/.jenkins/hs_err_pid36290.log

首先,基础知识:

我在许多其他配置中也遇到了同样的问题:使用 Java Hotspot 1.8.0_60,运行ning 通过 Apache Tomcat,并使用-Xms/-Xmx/-Xss 和类似选项的各种不同值。

我做了相当多的研究,思考我知道问题出在哪里,但不知道如何解决。我怀疑我 运行 正在处理提到的虚拟内存过度使用问题 here;来自 ulimit 的相关位:

--($:)-- ulimit -a
...
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) 8388608
stack size              (kbytes, -s) 8192
virtual memory          (kbytes, -v) 8388608
...

如果我以 root 身份将虚拟内存限制加倍,我可以启动 Jenkins,但我不想 运行 Jenkins 作为 root 用户。

另一个解决方法:具有 48 GB 内存和 24 个内核的即将退役的机器可以毫无问题地启动 Jenkins,尽管(我怀疑)只是勉强:根据 htop,它的虚拟内存占用刚好超过 8国标。因此,我怀疑内存过度使用问题会随着机器上处理器的数量而增加,这可能是 Jenkins 启动的线程数量与主机上存在的处理器数量成正比的结果。我通过 ps -eLf | grep jenkins | wc -l 粗略地捕获了线程数,发现线程数在 40 核机器上达到 114 左右,在 24 核机器上达到 84。

这个解释听起来合理吗?只要是...

  1. 有什么方法可以配置 Jenkins 以减少它在启动时生成的线程数?我尝试了讨论的论点 here 但是,正如所宣传的那样,它们似乎没有任何效果。
  2. 是否有任何可用的 VM 不受过度使用问题的影响,或者是否有其他一些配置选项可以解决该问题?

此时最明智的选择可能是 运行 虚拟化环境中的 Jenkins 将其可支配的资源限制在合理的范围内,但此时我对这个问题感兴趣级别,想知道如何让这个顽固的配置发挥作用。

编辑

这是 hs_error.log 文件中的一个片段,它指导了我的初步调查:

# There is insufficient memory for the Java Runtime Environment to continue.
# pthread_getattr_np
# Possible reasons:
#   The system is out of physical RAM or swap space
#   In 32 bit mode, the process size limit was hit
# Possible solutions:
#   Reduce memory load on the system
#   Increase physical memory or swap space
#   Check if swap backing store is full
#   Use 64 bit Java on a 64 bit OS
#   Decrease Java heap size (-Xmx/-Xms)
#   Decrease number of Java threads
#   Decrease Java thread stack sizes (-Xss)
#   Set larger code cache with -XX:ReservedCodeCacheSize=
# This output file may be truncated or incomplete.

这是我试过的几个命令行,结果都一样。

还尝试了许多其他配置。最终我不认为这里的问题是堆耗尽——这是 JVM 试图为自己保留太多的虚拟内存(在其中存储堆、线程堆栈等),而不是 ulimit 设置所允许的。据推测,这是之前链接的过度使用问题的结果,如果 Jenkins 生成 120 个线程,它会错误地尝试保留 120 倍于主进程最初占用的 VM space。

在使用该日志中建议的其他选项完成了我能做的事情后,我试图弄清楚如何减少 Jenkins 中的线程数以测试线程 VM 过度使用理论。

编辑 #2

根据 Michał Grzejszczak 的说法,这是与 Red Hat Enterprise Linux 6 一起分发的 glibc 的问题,如讨论的那样 here。这个问题可以通过显式设置环境变量 MALLOC_ARENA_MAX 来解决,在我的例子中是 export MALLOC_ARENA_MAX=2。如果不显式设置此变量,JVM 显然会尝试生成(8 x cpu 核心数)个线程,每个线程消耗 64M。我的 40 核心案例需要 northward 的 10 gigs 虚拟 ram,超过(本身)我机器上的 ulimit 8 gigs。将此设置为 2 可将 VM 消耗减少到大约 128 兆。

Jenkins 内存占用更多​​地与其管理的项目数量和大小相关,而不是 CPU 数量或可用内存。 Jenkins 应该 运行 在 1GB 堆内存上没问题,除非你有巨大的项目。

您可能错误配置了 JVM。 -Xmx 和 -Xms 参数管理堆 space JVM 可以使用。 -Xmx 是堆内存的限制,-Xms 是堆内存的起始值。堆是整个 JVM 的单个内存区域。您可以通过 JConsole 或 VisualVM 等各种工具轻松监控它。

另一方面,-Xss 与堆无关。它是此 JVM 进程中所有线程的线程堆栈的大小。由于 Java 程序往往会创建大量线程,因此将此参数设置得太大可能会阻止您的程序启动。通常这个值在 512kb 的范围内。在此处输入 512m 反而会使 JVM 无法启动。确保您的设置不包含任何此类错误(并且 post 您的内存配置也是如此)。