案发

你可能很难想象,压垮一台 32G 内存笔记本的,不是深度学习模型,也不是 3D 渲染,而是一个简简单单的 next dev

事情是这样的。

那天晚上,我像往常一样打开项目,敲下 pnpm next dev,打算继续写那个拖了一周的页面。一切看起来都很正常——终端启动、编译、热更新……直到我开始感觉到电脑的风扇在狂转。

我扫了一眼任务管理器,node.exe,内存占用:1.6GB

五分钟后,2.4GB。又过了几分钟,直逼 4GB

我当时的第一反应是:我代码里是不是写了什么死循环?还是哪个 useEffect 在无限请求?我停下所有操作,把浏览器切到后台,看着内存条的数字在静默中一点一点往上爬——没有触发任何代码执行,仅仅是 IDE 开着、终端挂着。

也就是说,进程在“闲着”的时候,也在疯狂吃内存。

这不是我写的 Bug。这是工具在自杀。


破案:不是代码,是路径

我把排查范围缩窄到 Turbopack——Next.js 16 默认搭载的那个号称“快 700 倍”的编译引擎。

由于是 Rust 实现的,它的编译缓存全权交由 SWC 管理,而 SWC 内部使用文件绝对路径作为缓存 Key。这本不是什么大问题,问题出在 Windows 上——Windows 的文件系统是不区分大小写的,但 SWC 的缓存 Key 逻辑是区分大小写的。

这就造成了一个恐怖的局面:

  • 项目路径是 D:\Code\JellyBit.Studio\food\cola
  • 某个模块被访问时,SWC 生成了一个 Key:JellyBit.Studio
  • 但当操作系统在底层 I/O 中返回了全小写的路径:jellybit.studio 时,SWC 认为这是一个全新的模块
  • 于是它重新编译,生成一个新缓存条目
  • 旧的缓存条目不会被清理,变成死数据
  • 每一次热更新,甚至每一次文件系统响应延迟,都会触发这个“造假过程”

结果就是:缓存越积越多,直到你把所有内存吃完。

我通过 Get-Process node 持续监控,确认了 CPU 几乎一直处于 idle 状态——不是运算压力,而是纯粹的内存泄漏。

更有意思的是,含 . 的路径(比如 JellyBit.Studio)还会被 SWC 解析为模块命名空间分隔符,导致缓存 key 的生成逻辑进一步异常。这相当于在一个原本就脆弱的机制上,再补了一刀。


问题很冷门,但教训很通用

一旦定位到问题,解决方案其实非常克制:

最简单有效的方法:把项目路径改成全小写、kebab-case。

之前之后
C:\Users\wo\IdeaProjects\JellyBit.Studio\food\colaC:\Users\wo\IdeaProjects\jellybit-studio\food\cola

就这么简单。没有改一行代码,没有升一个版本,问题彻底消失。

当然,你也可以选择——不改路径——通过禁用 Turbopack 来规避:

// next.config.js
module.exports = {
  turbopack: false,
}
最后修改:2026 年 05 月 28 日
如果觉得我的文章对你有用,请随意赞赏