Prhub

#44363 [Core] Freeze garbage collector in workers after model initialization

原始 PR 作者 tlrmchlsmth 合并时间 2026-06-04 23:39 文件变更 1 提交数 3 评论 4 代码增减 +8 / -0

执行摘要

冻结 worker GC 减少 P99 ITL 抖动

PR body 明确指出 'Drastically reduce P99 ITL in some cases (especially WideEP)',即降低高 expert 并行场景下的 P99 请求间延迟(inter-token latency),通过冻结 GC 避免其扫描静态对象(模型权重、KV cache、CUDA graphs)对推理的干扰。

该 PR 值得精读,尤其是对高吞吐低延迟推理服务有需求的团队。设计决策(仅在 worker 上线后冻结、shutdown 时解冻)简洁清晰,可作为 Python 服务性能优化的参考模式。此外,注意作者通过实验验证了 CUDA graph 捕获不受影响,避免了不必要的改动。

讨论亮点
  1. WoosukKwon 询问冻结 GC 是否真的对 CUDA graph 捕获有帮助,因为 PyTorch 默认不再调用 gc.collect()。作者 tlrmchlsmth 在测试后确认 CUDA graph 捕获时间无变化('Graph capturing finished in 56 secs, took 6.25 GiB' 前后一致),因此移除了 CUDA graph 捕获阶段的冻结,仅保留 worker 运行时冻结。
  2. njhill 肯定了变更的价值,并提到原本以为 engine core 和 frontend 进程已经做了类似操作,但 worker 进程遗漏了。

实现拆解

  1. 新增导入:在 vllm/v1/worker/gpu_worker.py 中导入 freeze_gc_heapmaybe_attach_gc_debug_callback,均来自 vllm.utils.gc_utils
  2. 冻结时机:在 compile_or_warm_up_model() 方法末尾、activate_triton_jit_monitor() 之后,调用 freeze_gc_heap() 冻结 worker 堆,并调用 maybe_attach_gc_debug_callback() 附加调试回调(如果启用了调试)。
  3. 解冻时机:在 shutdown() 方法的首行调用 gc.unfreeze(),确保进程退出前恢复 GC 正常行为,不干扰其他模块的清理逻辑。
文件 模块 状态 重要度
vllm/v1/worker/gpu_worker.py 工作进程 modified 5.67

关键源码片段

vllm/v1/worker/gpu_worker.py dependency-wiring

唯一修改的文件,在 `compile_or_warm_up_model` 末尾添加 `freeze_gc_heap()` 和 `maybe_attach_gc_debug_callback()`,在 `shutdown` 开头添加 `gc.unfreeze()`。

# vllm/v1/worker/gpu_worker.py ( 关键变更部分 )# 新增导入
from vllm.utils.gc_utils import freeze_gc_heap, maybe_attach_gc_debug_callbackdef compile_or_warm_up_model(self) -> CompilationTimes:
    # ... 模型加载、CUDA graph 捕获、kernel 预热等 ...
    # 所有预热完成,开始监控意外 JIT 编译
    from vllm.triton_utils.jit_monitor import activate as activate_triton_jit_monitor
    activate_triton_jit_monitor()
​
    # Freeze the worker heap so the GC won't scan static objects
    # (model weights, KV caches, CUDA graphs) during inference.
    freeze_gc_heap() # 冻结当前堆,防止 GC 扫描
    maybe_attach_gc_debug_callback() # 调试用(可选)
    return CompilationTimes(...)def shutdown(self) -> None:
    gc.unfreeze() # 解冻,确保正常清理
    # ... 原有的 shutdown 逻辑(kv transfer、NCCL 等)...

评论区精华

GC freeze 对 CUDA graph 捕获的影响 性能

WoosukKwon 质疑冻结 GC 是否有助于减少 CUDA graph 捕获时间,因为 PyTorch 已不再默认调用 `gc.collect()`。

结论:作者确认 CUDA graph 捕获时间无变化(56s vs 57s),因此移除了 CUDA graph 捕获阶段的冻结。 · 已解决

风险与影响

风险较低。变更仅添加两行函数调用,且在 shutdown 中保证了解冻。如果 gc.freeze() 在后续版本中有行为变更,或者某些深度学习库(如 HuggingFace tokenizer 或自定义扩展)依赖运行时 GC 回收临时对象,可能导致内存泄漏。但 gc_utils 模块应已有适当封装和调试支持。

直接影响所有 V1 GPU worker 进程,尤其是 WideEP 场景。冻结 GC 后,推理过程中不会再触发 GC 扫描,从而显著降低 P99 ITL 抖动。对内存占用影响极小(仅堆中现有对象被标记为永久)。用户无需修改配置或代码。

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论