ComfyUI 报 memory leak 告警怎么办:先分清两条文案,再做二分排查

2026-08-09

跑一晚上批量任务,第二天早上翻控制台,看到一行带 memory leak 字样的红字,第一反应通常是「完了,得重装」。先别动手。这条告警在 ComfyUI 里是有明确文案、明确指向的,而且它指的方向跟大多数人猜的不太一样——它基本不是在说 ComfyUI 核心漏了内存,而是在说有人还攥着模型不放

下面这套流程,是按 ComfyUI v0.31.0(2026-08-08)的 comfy/model_management.pycomfy/cli_args.py 的口径整理的。参数和日志文案会随版本变,跑之前先用 python main.py --help 对一遍。

一、现象:两条告警,原文长这样

源码里跟内存泄漏相关的告警有两条,文案是固定的,抄下来方便你 Ctrl+F:

Potential memory leak detected with model {类名}, doing a full garbage collect, for maximum performance avoid circular references in the model code.
WARNING, memory leak with model {类名}. Please make sure it is not being referenced from somewhere.

{类名} 的位置会被换成具体的模型类名。这个类名是本文后面所有排查动作的锚点,看到告警第一件事就是把它记下来,不要只截图一个「有报错」就去搜。

两条文案的差别不是随口写的:

第一条第二条
措辞Potential memory leak detectedWARNING, memory leak
是否带自救动作文案里明说 doing a full garbage collect文案里没有
给的方向avoid circular references in the model codemake sure it is not being referenced from somewhere

用大白话讲:第一条是「怀疑有泄漏,我先做一次完整垃圾回收兜一下,你回头把模型代码里的循环引用改掉,不然性能受影响」;第二条更硬,是「泄漏了,你自己去查还有谁在引用它」。第二条属于更严重的情形。

我要在这里就把话说死:这两条都不是「ComfyUI 崩了」的标志,第一条尤其不是——它的措辞就是 Potential(疑似),并没有断言一定发生了泄漏,而且文案自己交代了「已经做了一次完整垃圾回收」。真正需要你上手的,是它稳定复现、并且伴随内存或显存一路涨不回去。

二、怎么确认确实是这个问题:三个可执行动作

动作 1:确认告警文案本身,别拿别的报错来对号入座

只有上面两条原文算数。控制台里出现 torch.cuda.OutOfMemoryError,那是 OOM,不是泄漏告警——源码里 OOM 走的是单独定义的 OOM_EXCEPTION(在没有 CUDA 的路径上退化成 Exception),有自己的捕获分支,跟这两条告警不是一回事。同理,{N} models unloaded. 是正常的卸载日志,不是问题。

动作 2:把启动时的那几行基线抄下来

ComfyUI 启动时会打印几行可对照的信息,出问题前先把它们存好:

  • Total VRAM {:0.0f} MB, total RAM {:0.0f} MB —— 这台机器的总量基线
  • Set vram state to: {vram_state.name} —— 当前的 VRAM 状态机取值,取自枚举 DISABLED / NO_VRAM / LOW_VRAM / NORMAL_VRAM / HIGH_VRAM / SHARED
  • Enabled pinned memory {}(单位 MB)—— 有没有启用 pinned memory 以及上限
  • Using async weight offloading with {} streams —— 异步权重卸载有没有开、开了几个流
  • Requested to load {模型类名} —— 谁在被加载

第五行尤其关键:把 Requested to load 里的类名跟泄漏告警里的 {类名} 对上,你就知道是哪一类模型出的事。想让日志更细,用 --verbose,合法等级是 DEBUGDETAILINFOWARNINGERRORCRITICAL,不带值时等价于 DEBUG;也可以写成 --verbose LEVEL FILE 把这一路输出落到文件里,方便隔天回看。注意 DETAIL 这一级是 v0.30.0(PR #15064)才加的,老版本上没有。

动作 3:二分排查——这一步才是真正定位

告警文案给的两个方向,in the model codereferenced from somewhere,说的都是「有代码持有着模型对象」。在一台正常安装的 ComfyUI 上,能塞进这条链路的第三方代码,主要就是自定义节点。所以官方给了现成的开关:

python main.py --disable-all-custom-nodes

这条参数的 help 原意就是「不加载任何自定义节点」。用它跑同一个工作流(注意:工作流里如果用到了自定义节点,就得先换成能跑通的原生等价流程,否则你测的是「图跑不起来」而不是「有没有泄漏」)。

如果干净启动下告警消失,再往回二分。ComfyUI 给了配套参数:

python main.py --disable-all-custom-nodes --whitelist-custom-nodes NodeDirA NodeDirB

--whitelist-custom-nodes 的 help 原意是:在开启上一条的前提下,仍然加载指定的自定义节点目录。所以流程就是把你的节点目录列表对半切,一半放白名单里跑一轮,告警在哪半边就往哪半边继续切。对半切是标准二分:节点目录有三十个,五轮左右就能收敛到单个目录。

以上为按官方参数语义组合的示例,未逐项实测,以官方文档与 python main.py --help 的实际输出为准。

三、官方给的处置方向只有两条,别自己加戏

把两条告警的文案再读一遍,它给的处置就是全部:避免模型代码里的循环引用,以及确认还有谁在引用它

这意味着,定位到某个自定义节点之后,你手上的选项其实相当有限:

  1. 禁用它,或者用 --disable-all-custom-nodes + --whitelist-custom-nodes 长期只放行你确实要用的那几个。这是唯一你自己就能落地的做法。
  2. 换一个功能等价的实现,或者退回原生节点。
  3. 把告警原文、模型类名、复现步骤发给该节点的作者。代码不在你手里,改循环引用这件事得由维护它的人来做。

我必须把这句不好听的话讲清楚:定位到「是哪个节点」,不等于你能修好它。 这篇文章能保证的上限就是帮你把范围缩小到具体的节点目录,以及在修好之前用禁用的方式把损失控制住。任何声称「加这个参数就不漏了」的说法,在官方文案里都没有依据。

顺带提一句常被误当成解法的两个开关:--disable-smart-memory 的 help 是「强制积极地卸载到常规内存,而不是能留在显存时就留着」,它改的是卸载策略;--cache-none 的 help 是「降低 RAM/VRAM 占用,代价是每次运行都重新执行每个节点」。这两个可能让你的内存曲线好看一点,但它们都不是针对泄漏的修复,只是把症状压下去,而且各有明确代价——尤其 --cache-none 会让每次运行都全图重跑。

四、处置之后怎么验证

改完别只看一眼「没报错」就收工,按下面三条核:

  1. 同一个工作流连续跑多轮。泄漏的特征是「累积」,跑一次看不出来。重点看告警文案有没有再出现,以及出现的是哪一条——如果从第二条降级成偶发的第一条,说明情况变了但没清干净。
  2. 对照启动基线。重启后重新抄一遍 Total VRAM ... total RAM ...Set vram state to:,确认你在排查过程中没有顺手改掉别的东西(比如为了测试临时加过 --highvram,它会连带把 dynamic VRAM 关掉,那你后面看到的内存行为已经不是原来那套了)。
  3. 确认 {N} models unloaded. 还在正常出现。这行是卸载路径在工作的迹象;如果你为了「省事」加了 --gpu-only--highvram 让模型常驻,那就别再用「内存没降」来判断泄漏了,那是你要求的。

一个提醒:ComfyUI 的加载/卸载路径近几个版本改动很密——v0.23.0(2026-06-01)加了多线程从磁盘加载模型并支持 offload 到磁盘(PR #13802),v0.30.0(2026-08-03)改成用 pinning 基础设施、按 MRU 策略把权重加载到进程 RAM(PR #15027),v0.31.0(2026-08-08)又修了「Linux 无 swap 分区时不要 pin 太多内存」(PR #15266)。所以跨版本比内存曲线基本没有意义,验证一定要在同一个版本上做前后对比。

五、什么情况说明不是这个原因

这一节别跳过,很多人就是卡在这里一条道走到黑。以下几种情况看着都像泄漏,但走上面那套流程是白费功夫:

没有那两条告警,只是内存/显存占用高。 那多半是缓存和 pin 策略在按设计工作。默认缓存模式是 --cache-ram(RAM 压力缓存),不给值时 active 阈值是系统 RAM 的 10%(最小 2GB、最大 10GB),inactive 是系统 RAM 的 100%(最大 128GB)——数字本身就不小。--cache-lru N 的 help 直接写明「可能占用更多 RAM/VRAM」;--high-ram 在源码里会把 cache_classic 置真,等于隐含切到旧式(aggressive)缓存。占得多不等于漏。

RAM 被吃掉一大块,但曲线是平的。 先看 Enabled pinned memory {} 那一行。Windows 上 MAX_PINNED_MEMORY = ram * 0.40,源码注释写的是 # Windows limit is apparently 50%;非 Windows 系统的算式还会把 swap 总量算进来,并留出 4GB / 16GB 两道余量。想确认是不是 pin 的锅,用 --disable-pinned-memory 跑一轮做对照即可。另外源码里有 Could not get amount of swap memory on system.Could not read Windows swap usage; falling back to RAM-pressure pin eviction: %s 两条告警——「拿不到 swap 信息」是官方预期内的情况,会退回按 RAM 压力做 pin 淘汰,看到它不用慌。

你在 Linux 上、没有 swap 分区、版本低于 v0.31.0。 那条「Don’t pin too much memory on Linux systems with no swap partition.」(PR #15266)就是 2026-08-08 才修的,先升级再排查。

现象是「改一下 prompt 就整个重新加载模型」。 这跟泄漏是两回事。官方仓库 issue #14618 反映了「改动 prompt 后每次都重新加载模型」这一现象,该 issue 创建于 2026-06-24,标签为 Potential Bug(字面含义是「疑似 bug」,不是官方已确认),截至 2026-08-09 仍为 open,是当前评论数最高的开放 issue。请注意我们没有读过它的正文与评论,这里只能告诉你「有这么个开放中的现象记录」,不能给你根因。

报的是 OOM 崩溃而不是告警。 走 OOM 那条排查线,别在这篇里耗着。

你加了 --lowvram 觉得「没生效所以肯定是漏了」。 这是版本变化坑人的地方:源码里 dynamic VRAM 的启用判定是

def enables_dynamic_vram():
    if args.enable_dynamic_vram:
        return True
    return not args.disable_dynamic_vram and not args.highvram and not args.gpu_only and not args.novram and not args.cpu

即什么都不加时 dynamic VRAM 是的,而 --lowvram 的 help 原文写着「如果启用了 dynamic vram,这个选项不做任何事」。老教程里那句「显存小就加 --lowvram」在当前版本已经不成立。这个设计挺反直觉,但它跟泄漏无关。

六、什么时候该去提 issue

满足下面三条再去开 issue,否则大概率会被当成自定义节点问题关掉:

  1. --disable-all-custom-nodes 干净启动,告警依然稳定复现
  2. 同一个版本上能重复出现,不是升级前后混着比出来的;
  3. 你能给出告警的完整原文(含 {类名} 被替换后的实际类名)、完整启动命令、Total VRAM ... total RAM ...Set vram state to: 那两行,以及操作系统和显卡型号。

顺便给个心理预期:内存类的开放 issue 在这个仓库里存量不小,而且活得很久。比如 #4271「Flux.1 Dev, memory issue」创建于 2024-08-08,标签 Potential Bug,113 条评论,截至 2026-08-09 仍为 open;#14907「0.27.1 - Memory Usage Degraded even more AGAIN」创建于 2026-07-12,未打标签,截至 2026-08-09 也仍为 open。这两条我们同样只拿到了编号、标题、日期、标签和状态,没有读过正文和评论,所以既不能拿它们当你的根因,也不能拿它们当「官方已确认」——Potential Bug 这个标签的字面意思就是「疑似」。

把这个现实摆出来不是劝退。而是说:你能立刻拿回收益的动作,是二分定位 + 禁用/替换那个节点;提 issue 是给社区留证据的长线动作,两件事别搞混,更别指望提完就有人帮你修好。

延伸阅读


本文依据 ComfyUI 官方仓库(github.com/Comfy-Org/ComfyUI)的 README、comfy/cli_args.py、 release notes 与官方安全公告整理,核对日 2026-08-09,对应版本 v0.31.0; 文中引用的 issue 状态为该日期的快照。本文内容为官方文档与源码口径,非本机实测。 参数、默认值与功能随版本变动,请以官方文档与 python main.py --help 的实际输出为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。