Jenkins 内存句柄耗尽速查:master OOM、构建记录堆积与句柄泄漏
更新时间:2026-10-24。FAQ 速查页,面向 Jenkins 控制器跑着跑着界面卡死、日志里抛
java.lang.OutOfMemoryError: Java heap space、或构建突然报Too many open files的同学。Jenkins 内存不足不是单一故障,它有三张面孔:JVM 堆被撑爆(界面 502、构建排队不动)、文件句柄耗尽(构建写不了日志直接失败)、磁盘被构建记录和归档吃光(新构建起不来)。三张面孔背后是同一组病因:堆参数给小了、构建记录从不清理、插件或流水线持有的句柄没关、归档策略缺失、执行器数量超配。Jenkins 内存句柄耗尽的病因收敛在六根轴上:堆参数与负载不匹配、构建记录堆积、句柄泄漏、插件内存膨胀、归档无清理、executors 超配,顺一遍基本必中。如果是 agent 节点的 JVM 崩溃而不是控制器资源耗尽,转 Jenkins agent JVM 崩溃速查。
本文要回答的问题
OutOfMemoryError: Java heap space出现后,先看堆大小还是先找泄漏?Too many open files是构建脚本的问题还是 Jenkins 自身的问题?- 构建记录多少条算多,保留策略怎么配才不爆磁盘?
- 界面越来越慢、GC 日志里 Full GC 连发,是哪个插件在吃内存?
- 堆从 2g 调到 8g 还是 OOM,钱花到哪去了?
一、报错原文与典型现象
资源耗尽有三处现场:控制器日志($JENKINS_HOME/logs 或 systemd journal)、构建控制台输出、系统级计数器(控制器地址以 jenkins.example.com 占位,路径以 /proj/demo 占位):
# 控制器日志:堆耗尽,界面开始 502
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at hudson.model.Run.execute(Run.java:...)# 构建日志:句柄耗尽
java.io.IOException: Too many open files
at java.io.FileOutputStream.open0(Native Method)
Caused: java.io.IOException: Cannot write build log# 系统侧确认
$ jmap -histo <pid> | head # 堆里谁最大
$ lsof -p <pid> | wc -l # 句柄数逼近 ulimit
$ du -sh /proj/demo/jobs/*/builds # 构建记录占多少盘先定性再动手:堆耗尽看 jmap -histo 的大对象排名,句柄耗尽看 lsof 计数,磁盘耗尽看 jobs 目录体积——三个指标对应三条完全不同的修复路线,混着治只会反复。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| OutOfMemoryError: Java heap space,Full GC 连发 | 堆参数偏小或对象泄漏 | jmap -histo 看大对象;GC 日志 | 调大 -Xmx;按直方图找泄漏插件升级 |
| OutOfMemoryError: Metaspace | Groovy 脚本类加载器累积 | Metaspace 曲线只涨不跌 | 设 MaxMetaspaceSize 并升级 Jenkins 与插件 |
| Too many open files | 句柄泄漏或 ulimit 太低 | lsof -p 计数持续增长 | 定位泄漏插件;调大 LimitNOFILE 与 ulimit |
| jobs 目录几十 GB、磁盘写满 | 构建记录与归档不清理 | du -sh jobs/*/builds 对比 | 配丢弃旧构建策略;清历史 build |
| 界面慢、接口超时但堆没满 | 插件内存膨胀或线程堆积 | jstack 看阻塞线程;监控曲线 | 逐个禁用近期新增插件定位元凶 |
| 高峰期集中 OOM,平时正常 | executors 数超配内存总量 | 峰值并发构建数 × 单构建内存 | 降 executors 或按内存配额调度 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓分水岭:第一步不是调参数,是把报错归到「堆、句柄、磁盘」三类之一。报错原文里带 heap space 走左支用 jmap 找元凶,带 open files 或磁盘告警走右支用 lsof 与 du 定位;两条支路汇到同一个修复动作,但各自验证指标不同,复测时分别盯 GC 曲线与句柄计数。
四、逐条排查展开
堆参数与负载不匹配是最常见的根因。 默认装的 Jenkins 很多发行版只给 256m-512m 堆,装上几十个插件、跑上百个任务后必爆。症状是 GC 日志里 Full GC 间隔越来越短、每次回收不出多少内存,最后抛 heap space。处置:-Xmx 按「插件基线 + 并发构建数 × 单构建元数据」估算,中型实例 4g 起步;同时把 GC 换成 G1 并打开 -Xlog:gc* 记录,没有 GC 日志的调参都是盲调。
构建记录堆积是慢性病,拖垮的不止磁盘。 每个 build 目录里有日志、changelog、测试报告与归档链接,一个高频任务一天几十次构建,一年就是上万条记录。记录多不只是占盘——Jenkins 加载任务时要扫描历史构建,记录越多界面越慢、堆占用越高。处置:任务配置里开「丢弃旧的构建」,按天数与条数双上限(如 30 天或 100 条),流水线任务在 Jenkinsfile 里写 options { buildDiscarder(logRotator(daysToKeepStr: '30', numToKeepStr: '100')) },批量存量任务用脚本控制台统一刷一遍。
句柄泄漏要看曲线而不是单点计数。 lsof -p <pid> | wc -l 每小时采一次,持续上涨的才是泄漏——常见来源是某些插件打开的 HTTP 连接或文件流没关。确认泄漏后按「最近新装或升级的插件」逐个禁用二分定位。不泄漏但不够用的情况是 ulimit 太低:systemd 管理的 Jenkins 要改 unit 文件里的 LimitNOFILE=65536,改 /etc/security/limits.conf 对 systemd 服务不生效,这是反复踩的坑。
插件内存膨胀靠直方图现形。 jmap -histo:live <pid> 输出按实例数排序,排在前列的如果是某个插件的类(类名里带插件包名),元凶就是它。处置顺序:先查该插件有没有修复版本,升级优先;没有修复就评估能否替换;都不行就把用到它的任务迁移到独立控制器,别让它拖死主力实例。
归档策略缺失让 artifacts 悄悄吃掉所有空间。 构建产物默认留在控制器磁盘,大产物(镜像包、SDK、测试数据)几次构建就上 GB。处置:archiveArtifacts 只归档必要文件并配排除规则,大产物推制品库(Nexus/Artifactory/对象存储)后只留链接;控制器上 artifacts 随 buildDiscarder 一起轮换。
executors 超配是高峰期 OOM 的放大器。 控制器 executors 设为 CPU 核数的两倍是常见误配——每个并发构建都会在控制器上加载任务元数据与流水线状态,16 并发 × 每构建几百 MB 瞬时占用,4g 堆瞬间见底。处置:控制器 executors 压到 0-2,构建尽量下放到 agent 节点;必须留控制器的,按「堆总量 ÷ 单构建峰值」反推并发上限。
五、规范做法与预防
- 容量三账合一:堆、句柄、磁盘各设监控阈值,任一水位过 70% 告警,不等 OOM 发生。
- 保留策略模板化:buildDiscarder 写进共享库或 Job DSL 模板,新任务默认带,不靠人肉配置。
- GC 与资源日志常开:
-Xlog:gc*、句柄计数、jobs 目录体积进监控系统,趋势比阈值更早暴露问题。 - 插件准入评审:新插件上线前在灰度实例跑一周,盯内存与句柄曲线,膨胀的一律退回。
- 定期大扫除:每月跑一次 jobs 目录体积排行与句柄基线审计,异常任务当场配保留策略。
- 控制器瘦身:构建一律下 agent,控制器只调度,executors 趋零是资源稳定的第一原则。
这一篇在知识体系里的位置
本篇是 Jenkins 排错速查簇的「资源容量」入口:agent 侧 JVM 崩溃与 hs_err_pid 读法看 Jenkins agent JVM 崩溃速查;构建不 OOM 但卡死不动看 Jenkins 构建卡死速查;节点资源正常但连不上看 Jenkins 节点离线速查;本批同簇的还有 Jenkinsfile 语法错误速查 与 Jenkins 环境变量不生效速查。「先按报错原文把资源类型归堆、句柄、磁盘三类,再上对应计数器找元凶」这条主线对一切 JVM 服务的容量故障通用。
一句话总结
Jenkins 内存句柄耗尽先按报错原文分三类:heap space 走 jmap 直方图找泄漏对象、按并发负载重估 -Xmx;Too many open files 用 lsof 曲线区分泄漏与 ulimit 太低,泄漏二分定位插件、限额改 systemd 的 LimitNOFILE;磁盘爆多半是构建记录与归档不清理,buildDiscarder 双上限加制品库外置一次到位。Metaspace 型 OOM 靠上限参数加插件升级双管齐下,控制器 executors 趋零是根治超配的方向。容量三账(堆、句柄、磁盘)进监控告警、保留策略进模板,资源耗尽类故障基本绝迹。