You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Description of expected behavior and the observed behavior
When you create a reference to another parameter, a hardref cycle is formed between the two that remains unbroken, causing all relevant objects to never be collected, until all of them no longer have an anchoring ref. Further, clobbering the reference by setting the Parameter to a non-referenced value does not remove the Watcher keeping the objects alive.
Complete, minimal, self-contained example code that reproduces the issue
import param
import weakref
import gc
class View(param.Parameterized):
n1 = param.Number(allow_refs=True)
def _clear_refs(self):
param_private = self._param__private
for name in param_private.refs:
if name in param_private.async_refs:
param_private.async_refs.pop(name).cancel()
for _, watcher in param_private.ref_watchers:
dep_obj = watcher.cls if watcher.inst is None else watcher.inst
dep_obj.param.unwatch(watcher)
self._param__private.ref_watchers = []
self._param__private.refs = {}
class Parent(param.Parameterized):
n1 = param.Number()
class ViewFactory:
def __init__(self) -> None:
self._view = weakref.WeakValueDictionary()
@property
def view(self):
if 'view' not in self._view:
t = Parent()
self._view['view'] = t
else:
t = self._view['view']
return t
fact = ViewFactory()
view1 = View(n1=fact.view.param.n1)
view2 = View(n1=fact.view.param.n1)
weakref.finalize(view1, lambda: print('finalized view1'))
weakref.finalize(view2, lambda: print('finalized view2'))
print(view1.n1)
print(view2.n1)
fact.view.n1 = 1
print(view1.n1)
print(view2.n1)
# let's clobber view1's ref
view1.n1 = 0
fact.view.n1 = 2
print(view1.n1)
print(view2.n1)
# hold a view1 weakref so we can access after del
ref = weakref.WeakValueDictionary(view1=view1)
del view1
gc.collect()
# nothing
# let's manually clear out the references
ref['view1']._clear_refs()
gc.collect()
# now it should be finalized
del view2
gc.collect()
# removal of the last referring object will break the hardref cycle and finally cause them all to be collected.... but if at least 1 still exists during collection, the problem will grow unbounded
The text was updated successfully, but these errors were encountered:
ALL software version info
Python 3.12
Param 2.1.0
Description of expected behavior and the observed behavior
When you create a reference to another parameter, a hardref cycle is formed between the two that remains unbroken, causing all relevant objects to never be collected, until all of them no longer have an anchoring ref. Further, clobbering the reference by setting the Parameter to a non-referenced value does not remove the Watcher keeping the objects alive.
Complete, minimal, self-contained example code that reproduces the issue
The text was updated successfully, but these errors were encountered: