viable/strict/1790888005: [dynamo] Don't let observed exceptions pin the Python stack (#197567)
PyTorch 发布 viable/strict/1790888005 变更(#197567),标题为 [dynamo] Don't let observed exceptions pin the Python stack。证据说明:从 tracer 中抛出的 ObservedException 会与其自身 traceback 形成引用环,只有循环 GC 能打破;traceback 覆盖 raise 时刻整个存活 Python 栈,因此在下次 GC 前该环会钉住 Dynamo 之下的所有帧,包括用户帧及其局部变量引用。根因是 InstructionTranslatorBase.exception_handler 在找不到处理器时重新抛出 raised_exception,CPython 在退出时把帧追加到异常 traceback,而帧仍通过 cell 持有该异常。修复方式是用 try/finally 包裹并在退出时显式 del 该参数,同时让 bubble_exception_to_interpreter 以参数接收异常而非闭包捕获。
Development
- First Reportviable/strict/1790888005: [dynamo] Don't let observed exceptions pin the Python stack (#197567)PyTorch Core
- Current Assessment判断:这类修复不改变模型能力或商业格局,但反映编译式框架在长驻训练/推理进程中对内存驻留的敏感度上升。对以 torch.compile 为默认路径的团队,异常路径的内存行为属于稳定性预算的一部分。可验证信号:后续 PyTorch 版本说明或 issue 中是否出现同类「异常钉住栈」的修复与回归测试。Agent Pulse · analysis
PyTorch 的 viable/strict/1790888005 分支合入 #197567,修复 torch.compile 的 Dynamo 组件中一处异常引用环问题。证据指出:ObservedException 从 tracer 抛出后与自身 traceback 构成环,只能由循环 GC 回收;由于 traceback 覆盖 raise 点的整个存活 Python 栈,在下次 GC 之前该环会钉住 Dynamo 以下的所有帧,包括用户帧及其局部变量所引用的对象。根因是 InstructionTranslatorBase.exception_handler 在无处理器时重新抛出 raised_exception,CPython 退出时把帧追加进异常 traceback,而帧仍以 cell 形式持有该异常,形成 exception→traceback→frame→cell→exception 的环。修复显式模仿 CPython 对 except ... as e 的隐式删除:用 try/finally 包裹并在退出时 del 参数,并让 bubble_exception_to_interpreter 改为以参数接收异常而非闭包捕获。
这是一处典型的异常生命周期与 GC 交互缺陷:闭包捕获使异常被 cell 持有,从而在 traceback 链上形成环,延迟回收并放大内存驻留。修复方向(显式 del、把闭包捕获改为参数传递)与 CPython 对 except ... as e 的处理一致,属于低风险、语义等价的改动。可验证的下一信号:在包含异常路径的 torch.compile 场景下,观察 GC 周期之间进程 RSS 与存活帧数量是否不再随异常次数线性增长。
判断:这类修复不改变模型能力或商业格局,但反映编译式框架在长驻训练/推理进程中对内存驻留的敏感度上升。对以 torch.compile 为默认路径的团队,异常路径的内存行为属于稳定性预算的一部分。可验证信号:后续 PyTorch 版本说明或 issue 中是否出现同类「异常钉住栈」的修复与回归测试。
对使用 torch.compile 的团队,异常路径的内存驻留会直接影响长驻服务的稳定性与容量规划;该修复降低因异常累积导致的 OOM 风险,减少为规避而关闭编译或频繁重启的运维成本。可验证信号:在相同异常率下,服务实例的峰值内存与重启频率是否下降。
若该修复进入稳定版本,异常密集的编译路径内存曲线应更平滑;反之若仍出现 GC 间隔内的驻留峰值,说明还有其它闭包或 traceback 持有路径。可验证信号:在固定异常注入频率下对比修复前后 GC 前后 RSS 差值。