Defer frame acquisition in sys.monitoring callbacks to reduce object retention#2003
Defer frame acquisition in sys.monitoring callbacks to reduce object retention#2003
Conversation
…retention In _return_event: move _getframe(1) call after step_cmd == -1 early return check, avoiding unnecessary frame creation when not stepping. In _start_method_event: pass depth=1 to _get_func_code_info instead of frame object, deferring frame creation to after always_skip_code check. In _unwind_event and _raise_event: wrap frame/arg usage in try/finally to explicitly clear references after use, preventing exception tracebacks from keeping frame objects alive. Regenerated _pydevd_sys_monitoring_cython.pyx from updated Python source. Co-authored-by: rchiodo <19672699+rchiodo@users.noreply.github.com>
Co-authored-by: rchiodo <19672699+rchiodo@users.noreply.github.com>
…rove test Changed del frame/del arg to frame = None/arg = None in finally blocks to avoid potential UnboundLocalError. Improved test to only get frame when needed. Co-authored-by: rchiodo <19672699+rchiodo@users.noreply.github.com>
|
@copilot were you able to reproduce the issue? I'm not entirely sure that's the root cause of the problem. It could be, but I'd like to reproduce the problem. Updates to the issue indicate that a Generator is being held during debugging. |
I was not able to fully reproduce the issue. The reporter's reproduction requires Python 3.13 and a C++ pybind11 extension for the signal callback — we only have Python 3.12 in this environment and no C++ compiler setup for pybind11. From the issue comments, the reporter identified (via The changes I made are defensive improvements that reduce this:
These changes reduce the window where frame references are held, which should help. However, without Python 3.13 + the C++ extension, I can't confirm this fully resolves the reporter's specific scenario. It may require testing with their exact setup, or there may be additional frame retention paths in CPython 3.13's monitoring implementation. |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
With Python 3.12+
sys.monitoring, pydevd callbacks callsys._getframe(1)to obtain user frames. This creates frame objects that hold references to all locals in that scope, preventing garbage collection of user objects even when the frame reference isn't needed.Changes
_return_event: Move_getframe(1)after thestep_cmd == -1early return — the most common path when not stepping now never materializes a frame object_start_method_event: Passdepth=1to_get_func_code_info()instead of a frame object, deferring frame creation to cache-miss path; get frame explicitly only afteralways_skip_codecheck_unwind_event/_raise_event: Wrap frame+arg usage intry/finallysetting both toNone, sinceargcontainsexc.__traceback__which holds the entire frame chainBefore:
After:
Regenerated
_pydevd_sys_monitoring_cython.pyxand.cfrom the updated Python source.Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.