zai-org / zai-org/feedback

[Bug] 3.10.1 (Linux x64) zcode-host-local-1 会话期间单 inotify 实例累积 65k+ watch 耗尽系统 fs.inotify.max_user_watches,导致其他应用 ENOSPC 启动失败

Open
#458 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

priority: P2
Dominant language
No language data
Stars
22
Forks
1
PR merge metrics
No merged PRs in 30d

Description

提交前确认 · Pre-submission checklist
  • 我已搜索过现有 issue,确认这不是重复(#374 是 V8 堆内存问题,与本条 inotify watch 耗尽不同)
  • 我已阅读 CONTRIBUTING.md
问题类别 · Category

性能 · Performance

涉及的 Agent 框架 · Agent framework

ZCode Agent(自研)

严重程度 · Severity

影响体验 · Major(ZCode 本身可用,但耗尽系统全局 inotify 配额,导致其他应用无法启动)

复现频率 · Reproducibility

偶现 · Sometimes(依赖会话内的文件操作规模)

问题描述 · Description

ZCode 桌面端的本地宿主进程 zcode-host-local-1 在会话进行中会在单个 inotify 实例上累积 65,000+ 个 watch,几乎占满 Linux 默认的 fs.inotify.max_user_watches = 65536 上限,导致同一用户下所有其他依赖文件监视的程序启动失败。本例中 dsh(DeepSeek Harness)启动时 chokidar watch 配置文件直接崩溃:

Error: ENOSPC: System limit for number of file watchers reached,
watch '/home/pdai/.dsh/profiles/headless/cordis.yml'

现场测量(Ubuntu 24.04,fs.inotify.max_user_watches=65536):

$ # 按进程统计 inotify watch 数
65131  208808  zcode-host-loca     <- ZCode 宿主,占 99.5%
49     203246  xdg-desktop-por
38     203294  gsd-xsettings
...
用户全部进程合计 65418 / 65536

关键观察:

  1. 65,128 个 watch 全部挂在 zcode-host-local-1同一个 inotify fd 上(watch descriptor 编号连续到 0xfe68),形态是 chokidar 逐文件/逐目录添加的非递归 watch(mask 0xfc6),即 watcher 在递归监视一个巨型目录树(我的主目录下仅一个工程就有 71k 个文件)。
  2. 抽样将被 watch 的 inode 反查文件系统,多数已不存在find / -xdev -inum ... 无结果)——watch 目标是已删除/被替换的文件,属于未随 unlink 清理的陈旧 watch。
  3. 会话活动结束后 watch 数回落到 0(约十几分钟后复测同一 fd 为 0),说明累积是会话生命周期内持续占满配额,而非永久泄漏;但只要会话在跑,其他应用就一直拿不到 watch。
  4. 该宿主进程在用户未主动使用 ZCode 时也可能存在(后台常驻),因此“没开 ZCode”的机器同样会被耗尽配额。
复现步骤 · Steps to reproduce
  1. Linux(默认 fs.inotify.max_user_watches=65536)上打开 ZCode 桌面端,进入一个包含大目录树(数万文件,如 pnpm workspace)工作区的会话。
  2. 让会话执行文件系统范围的分析操作(如全盘 find / 跨目录 grep,或正常使用一段时间)。
  3. 另开终端统计:for fd in $(find /proc/$(pgrep -f zcode-host-local)/fd -lname 'anon_inode:inotify'); do grep -c '^inotify' /proc/$(pgrep -f zcode-host-local)/fdinfo/${fd##*/}; done —— 可观察到单个 fd 上 watch 数达到数万。
  4. 启动任何需要文件监视的其他程序(如 dsh --profile headless "hi"),得到 ENOSPC: System limit for number of file watchers reached
期望表现 · Expected behavior
  • 宿主进程对 watch 数量有上限/去重(LRU、按目录粒度聚合),不应无限逼近系统 max_user_watches
  • 被监视文件删除后 watch 应及时移除;
  • 或改用递归 inotify / fanotify 等 O(目录数) 而非 O(文件数) 的方案。
实际表现 · Actual behavior

单个 inotify 实例累积 65k+ watch(含已删除 inode 的陈旧 watch),占满用户级 inotify 配额,导致 dsh、编辑器等无关应用全部 ENOSPC 启动失败;需要等会话结束或调大系统 sysctl 才能恢复。

ZCode 版本 · ZCode version

3.10.1

设备 / 系统 / 浏览器 · Device / OS / Browser

Linux 桌面(Ubuntu 24.04.4 LTS,kernel 7.0.0-30-generic,x64,AppImage /tmp/.mount_ZCode-*

截图 / 录屏 / 日志 · Screenshots / Recordings / Logs

见上文内嵌的现场测量与报错。规避方案(供其他遇到的用户参考):

sudo sysctl fs.inotify.max_user_watches=524288 fs.inotify.max_user_instances=512
# 并持久化到 /etc/sysctl.d/

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the watch accumulation in the zcode-host-local-1 process with the supplied /proc command on a large workspace, then inspect how chokidar watches are created and removed during a session. Done means deleted or replaced targets no longer leave stale watches, watch usage remains bounded, and another watcher such as dsh can start without ENOSPC.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux
Domain
desktop, operating-systems, performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.