Prhub

#20697 Fix VRAM leak in overlap scheduling with structured output (#20640)

sgl-project/sglang · 作者 Cishoon · 合并时间 2026-03-23 08:07

分析状态 已生成
文件变更 2提交数 5 · 评论 5
代码增减 +17 / -0
bugfix performance scheduling

执行摘要

修复在启用重叠调度和结构化输出时的 VRAM 泄漏问题。

根据Issue #20640,在启用extra_buffer(重叠调度)和结构化输出时,VRAM会缓慢但持续增长,导致生产环境几小时后出现OOM错误和模型重启。问题仅在这两个条件同时满足时触发,影响系统稳定性。

建议工程团队精读此PR,重点关注闭包环境下GPU张量生命周期的管理策略,可作为异步调度中内存优化的参考案例。

讨论亮点

审核中,主要讨论点围绕VRAM泄漏的机制。hnyls2002询问为何VRAM持续增长而非仅延迟一轮释放,Cishoon解释在tp_worker.py中,重叠调度创建的delay_sample_func闭包捕获了张量并保持引用,导致无法及时释放。双方确认修复方案合理,无重大争议。

实现拆解

实现方案涉及两个关键文件:在model_runner.py_preprocess_logits方法中,设置sampling_info.vocab_mask = None以在应用掩码后立即释放GPU张量;在scheduler.pylaunch_batch_sample_if_needed方法中,设置batch_result.delay_sample_func = Nonelogits_output.next_token_logits = None,以断开闭包对forward_batchlogits_output的引用,从而促进内存回收。

文件 模块 状态 重要度
python/sglang/srt/managers/scheduler.py scheduler modified 7.0
python/sglang/srt/model_executor/model_runner.py model_executor modified 7.0

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

关键符号

launch_batch_sample_if_needed _preprocess_logits

评论区精华

VRAM 泄漏机制讨论 正确性

hnyls2002 询问 VRAM 为何持续增长而非延迟释放,Cishoon 解释闭包引用导致张量无法及时回收。

结论:双方确认修复方案有效,解决了引用持有问题。 · 已解决

风险与影响

风险较低,变更仅涉及引用置空,不改变核心业务逻辑。但需注意潜在副作用:如果下游代码错误依赖这些已释放的张量(如vocab_masknext_token_logits),可能引发异常;尽管测试显示内存稳定,但缺少单元测试覆盖具体场景。

直接影响是解决了生产环境中的内存泄漏问题,提高了系统可靠性和性能。影响范围限于使用重叠调度和结构化输出的场景,对普通用例无影响,但有助于提升整体资源利用率。

引用管理变更 缺少测试覆盖

关联 Issue

#20640 [Bug] Qwen3.5+extra_buffer video memory leak during structured JSON response generation.

完整报告

执行摘要

该PR修复了在启用重叠调度(extra_buffer)和结构化JSON输出时,因闭包持有GPU张量引用而导致的VRAM泄漏。通过及时释放关键张量,解决了内存持续增长直至OOM的问题,提升了系统稳定性,建议关注其内存管理策略。

功能与动机

根据Issue #20640,在生产环境中使用Qwen3.5模型时,启用extra_buffer并请求结构化输出会导致VRAM缓慢但持续增长,几小时后引发OOM错误。此问题仅在两个条件同时满足时触发:重叠调度激活并创建闭包,以及基于语法的结构化输出分配vocab_mask。修复旨在消除这一内存泄漏,确保资源高效利用。

实现拆解

  • scheduler.py:在launch_batch_sample_if_needed方法中,添加代码将batch_result.delay_sample_func设为None,并清理logits_output.next_token_logits,以断开闭包对张量的引用。
    python batch_result.delay_sample_func = None if batch_result.logits_output is not None: batch_result.logits_output.next_token_logits = None
  • model_runner.py:在_preprocess_logits方法中,设置sampling_info.vocab_mask = None,在应用掩码后立即释放GPU张量。
    python sampling_info.vocab_mask = None
    这些改动共同确保张量在不再需要时被及时回收,防止内存累积。

评论区精华

审核讨论中,hnyls2002提出疑问:"为什么VRAM会持续增长而不是仅延迟一轮释放?" Cishoon解释:"在tp_worker.py中,重叠调度创建的delay_sample_func闭包捕获了forward_batchlogits_output,导致张量保持引用。" 双方最终确认修复方案合理,无进一步争议。

风险与影响

  • 风险:变更仅涉及引用置空,核心逻辑未变,但若下游代码错误依赖已释放张量(如vocab_mask),可能引发异常;缺少单元测试覆盖具体泄漏场景。
  • 影响:直接解决了生产环境OOM问题,提高了系统可靠性;影响范围限于重叠调度和结构化输出场景,对普通用户无影响,但优化了整体内存管理。

关联脉络

此PR独立修复了特定内存泄漏,未在近期历史PR中发现直接关联(如PR 20625涉及中间件bug,PR 20862为扩散模型功能)。它反映了在异步调度中管理GPU张量生命周期的重要性,可能为类似内存优化提供借鉴。

参与讨论