Jenkins agent JVM 崩溃速查:hs_err_pid 日志读法、堆内存与容器限额
更新时间:2026-10-24。FAQ 速查页,面向构建跑到一半 agent 突然掉线、工作目录里多出
hs_err_pid*.log、或控制台甩出Error occurred during initialization of VM的同学。Jenkins agent 的本质是一个跑在执行节点上的 Java 进程(agent.jar),JVM 崩溃分两大类剧本:一类是 JVM 自身致命错误产出 hs_err_pid 崩溃日志(段错误、内部断言失败),一类是 JVM 还没跑起来或刚跑起来就被环境掐死(堆参数不合法、容器内存限额触发 OOM Killer)。Jenkins agent JVM 崩溃的病因收敛在六根轴上:堆内存给得太小、Metaspace 被类加载撑爆、JDK 版本本身有缺陷、容器 cgroup 限额让操作系统杀了 JVM、插件带的本地库(JNI)段错误、以及 agent 掉线被误判为崩溃。顺一遍基本必中。如果是节点压根连不上而不是 JVM 崩溃,转 Jenkins 节点离线速查。
本文要回答的问题
- 工作目录里冒出
hs_err_pid12345.log,先看哪几行定死因? There is insufficient memory for the Java Runtime Environment to continue是堆不够还是物理内存不够?- Docker/K8s 里 agent 反复重启,退出码 137 是什么信号?
- 升级 JDK 后才崩,回退还是打补丁?
- agent 掉线但节点上没有崩溃日志,算 JVM 崩溃吗?
一、报错原文与典型现象
JVM 崩溃的现场分三处:构建日志尾部、节点工作目录的 hs_err_pid 文件、以及系统日志(控制器地址以 jenkins.example.com 占位,路径以 /proj/demo 占位):
# 构建日志尾部:agent 通道被撕断
java.nio.channels.ClosedChannelException
Caused: java.io.IOException: Backing channel 'JNLP4-connect
connection from <节点地址>' is disconnected.# hs_err_pid12345.log 头部(节点工作目录)
# A fatal error has been detected by the Java Runtime Environment:
# SIGSEGV (0xb) at pc=0x00007f2a4c1d..., pid=12345, tid=...
# JRE version: OpenJDK Runtime Environment (11.0.2+9)
# Problematic frame:
# C [libc.so.6+0x15f6a0]# 启动即失败:堆参数与物理内存不匹配
There is insufficient memory for the Java Runtime Environment
to continue.
# Cannot create GC thread. Out of system resources.
# K8s 里容器被杀
container jnlp ... reason: OOMKilled, exitCode: 137读现象先分两类:产出 hs_err_pid 文件的是 JVM 内部致命错误(真崩溃);连文件都没有、只有退出码或 OOMKilled 字样的是外部环境把 JVM 杀了(环境杀)。两类修法完全不同,先定性。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| hs_err_pid 报 SIGSEGV、Problematic frame 在 libc/JNI 库 | 插件或本地库的 JNI 段错误 | 看日志 Problematic frame 所在库名 | 升级相关插件;隔离用到该库的构建 |
| insufficient memory ... Out of system resources | 堆/线程栈需求超物理内存 | 节点 free -h 对比 -Xmx 参数 | 调小 -Xmx 或给节点加内存 |
| Metaspace 耗尽 java.lang.OutOfMemoryError: Metaspace | 类加载器泄漏(Groovy 脚本热加载) | 连发构建观察 Metaspace 只涨不跌 | 设 -XX:MaxMetaspaceSize;升级 Jenkins 与插件 |
| 只在某个 JDK 版本崩,换版本就好 | JDK 自身缺陷 | 对照 JDK 发行注记已知缺陷 | 换维护更新的 JDK 小版本 |
| 容器退出码 137 / OOMKilled | cgroup 限额 < JVM 堆+堆外 | 容器事件里 OOMKilled 字样 | 容器限额调大;或用 -XX:MaxRAMPercentage 对齐 |
| agent 掉线但无 hs_err_pid、无 OOM 痕迹 | 网络断/节点被回收,非 JVM 崩溃 | 节点系统日志与网络抓包 | 按掉线处理,排查网络与保活参数 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓分水岭:先到节点工作目录看有没有 hs_err_pid 文件,这是「JVM 真崩溃」与「环境杀」的分界线。有文件走左支读 Problematic frame;没有文件走右支查 OOM Killer 与容器事件。两条支路最终都汇到「版本与限额」两个修复点。
四、逐条排查展开
hs_err_pid 日志读法:三段定死因。 这份文件是 JVM 临终遗言,读三段就够:第一段 Problematic frame 指明崩在哪个库——C [libc.so...] 或某个插件带的 .so 指向本地代码段错误,J 开头指向 JIT 编译的 Java 代码,V 开头是 JVM 内部问题;第二段 Stack 看崩溃时线程在干什么;第三段 Memory 段与 system 段确认当时内存水位与机器配置。拿到 frame 所在库名基本就知道去升级哪个插件或哪个组件。
堆太小:报文说 insufficient memory 不一定是物理机没内存。 JVM 启动时要一次性向操作系统申请 -Xmx 上限的地址空间加 GC 线程栈。节点上并行跑多个 agent、每个都配大堆时,物理内存超卖,后启动的 JVM 就报 Cannot create GC thread. Out of system resources。处置:进节点配置页看 agent.jar 的 JVM 参数(高级 → JVM options),把 -Xmx 降到合理值(agent 进程多数场景 512m-1g 足够,大堆应给构建里跑的 Maven/Gradle 而不是 agent 本身),或在节点上加执行器数量与内存的配额约束。
Metaspace 耗尽是 Jenkins 平台的慢性病。 症状是 agent 或控制器跑几天后抛 OutOfMemoryError: Metaspace,连发构建让曲线只涨不跌。根因通常是流水线 Groovy 脚本每跑一次编译出新类、旧的类加载器又因持有引用回收不掉。处置两步:给 JVM 设 -XX:MaxMetaspaceSize 让崩溃提前暴露而不是拖垮整机;再把 Jenkins 与各插件升到维护版本——历史上多个版本修过类加载器泄漏,升级比调参治本。
JDK 版本缺陷:崩得「换版本就好」就是铁证。 某个小版本 JIT 编译器或 GC 有缺陷,会在特定代码路径稳定 SIGSEGV。验证方法极简单:同一构建换相邻小版本的 JDK 跑,好了就是版本问题。处置不要回退老版本躺平,去 JDK 发行注记里搜 hs_err_pid 里的帧符号,多数有对应修复版本,直接跳到修复版之后。
容器退出码 137 是 cgroup 在动手。 137 = 128 + 9(SIGKILL),配合 K8s 事件的 OOMKilled 字样,说明容器内存用量越过了 cgroup limit,内核挑了最大的进程——JVM——杀掉。经典坑:JVM 老版本不认容器限额,按宿主机内存算出巨大默认堆,构建一上负载就爆。处置:JDK 8u191+/11 之后用 -XX:MaxRAMPercentage=75.0 让堆跟随容器限额;同时把容器 limit 调到「堆 + 堆外(Metaspace、线程栈、本地库)+ 余量」,只调一边都会复发。
崩溃现场的保留动作要在处理之前。 工作目录会被下次构建复用,hs_err_pid 文件不及时捞走就会被覆盖;同时把节点的 dmesg、容器事件、构建日志尾部三段一起存档,三者交叉才能还原「JVM 先崩还是环境先杀」的时序。养成先存档后修复的习惯,比任何调参都值钱。
无崩溃日志的掉线别按 JVM 崩溃治。 构建日志只有 ClosedChannelException、节点上既无 hs_err_pid 也无 OOMKilled,多半是网络抖动、节点被云厂商回收或虚拟机被挂起。这类按 Jenkins 节点离线速查 的通道保活与重连路线处理,不要浪费时间调 JVM 参数。
五、规范做法与预防
- agent JVM 参数模板化:
-Xmx、MaxMetaspaceSize、MaxRAMPercentage三项写进节点配置模板,不逐节点手填。 - JDK 版本白名单:团队钉死 1-2 个验证过的 JDK 小版本,升级先在灰度节点跑满一周。
- 崩溃日志打捞:hs_err_pid 文件默认写在工作目录,配置归档或集中收集,别让现场被下次构建清掉。
- 容器限额与堆对齐:容器 limit、JVM 堆、堆外三部分做一张容量账,limit 至少留 25% 堆外余量。
- 节点资源监控:内存水位、OOMKilled 事件接入告警,崩溃前兆比崩溃本身更值得看。
- 执行器与内存联配:单节点执行器数 × 单构建内存峰值 ≤ 节点可用内存,超卖配置是批产崩溃的温床。
这一篇在知识体系里的位置
本篇是 Jenkins 排错速查簇的「进程级故障」入口:JVM 能正常跑但任务缺依赖看 Jenkins 缺动态库速查;崩溃由插件版本缺陷引起、升级拿不准看 Jenkins 插件版本不兼容速查;无崩溃日志的掉线排查走 Jenkins 节点离线速查;权限层的 AccessDeniedException 与进程故障是两条平行线,看 Jenkins 权限不足速查。「先看 hs_err_pid 定真崩溃与环境杀、再按 frame 或限额修复」这条主线对一切 JVM 进程崩溃通用。
一句话总结
Jenkins agent JVM 崩溃先分两类现场:有 hs_err_pid*.log 的是 JVM 真崩溃,读 Problematic frame 定崩在哪个库——本地库帧找插件、JIT/JVM 帧换 JDK 小版本;没有日志只有退出码 137 或 OOMKilled 的是环境杀,容器限额与 JVM 堆要用 MaxRAMPercentage 对齐并留足堆外余量;insufficient memory 多半是节点堆参数超卖物理内存,调小 agent 的 -Xmx。Metaspace 型 OOM 是 Groovy 类加载器泄漏的慢性病,设上限加升级插件双管齐下。JDK 版本白名单、崩溃日志集中收集、节点资源告警三件事入库,JVM 崩溃基本绝迹。