Closed
Description
Bug report
Bug description:
I discovered this bug while working on pytorch/pytorch#124302.
It looks like calling getattr_static
is causing an object to be reference leaked:
import gc
from inspect import getattr_static
import weakref
class C1:
pass
def main():
obj = C1()
weakref.finalize(obj, lambda: print("obj deleted!"))
class C2:
def __init__(self):
self.obj = obj
c2 = C2()
getattr_static(c2, "bad", None)
print("done main!")
main()
gc.collect()
print("done!")
Output:
done main!
done!
obj deleted!
If I comment out the getattr_static
line, the output is as expected:
done main!
obj deleted!
done!
It looks like this PR #104267 indirectly cached calls to getattr_static
, which is resulting in reference leaks. Perhaps this cache needs to use weak references?
Original PyTorch code for reference (torch.compile
calls getattr_static
on mod
at some point):
import torch
import gc
import sys
import weakref
from inspect import getattr_static
def dbg(o):
refs = gc.get_referrers(o)
print(len(refs), sys.getrefcount(o))
return refs
gm_list = []
def backend(gm, _):
gm_list.append(weakref.ref(gm, lambda _: print("gm deleted")))
# breakpoint()
return gm
def main():
param = torch.nn.Parameter(torch.randn(5, 5))
class Mod(torch.nn.Module):
def __init__(self):
super().__init__()
self.param = param
def forward(self, x):
return self.param * x
mod = Mod()
ref = weakref.ref(param, lambda _: print("obj deleted"))
opt_mod = torch.compile(mod, backend=backend)
print(opt_mod(torch.randn(5, 5)))
return ref
ref = main()
gc.collect()
print("done!")
print(ref)
CPython versions tested on:
3.12
Operating systems tested on:
Linux