import gc import sys import weakref def run(): class C: def __iter__(self): return self def __next__(self): raise StopIteration obj = C() for _ in range(10_000): for _ in obj: pass return weakref.ref(C) ref = run() gc.collect() print("jit enabled:", sys._jit.is_enabled()) print("leaked:", ref() is not None)
This looks to be caused by value-recording uop (in the RECORD family) taking a strong reference to an object not being decref'd when traces are rewound
{ _PyUOpInstruction *curr = uop_buffer_last(trace); while (curr->opcode != _SET_IP && uop_buffer_length(trace) > 2) { trace->next--; curr = uop_buffer_last(trace); } if (curr->opcode == _SET_IP) { int32_t old_target = (int32_t)uop_get_target(curr); curr->opcode = _DEOPT; curr->format = UOP_FORMAT_TARGET; curr->target = old_target; } goto done; }
CPython main branch
macOS
pythongh-157875: Fix reference leak when a JIT trace is rewound
Activity
pythongh-157875: Fix reference leak when a JIT trace is rewound