-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix CallbackRegistry memory leak #19480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
458d5cd
f35521a
baca32b
5fe328e
e7d6f12
1411fe2
ab10d45
9cfbab6
f1d3f16
eed6906
3204907
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -197,16 +197,17 @@ def __setstate__(self, state): | |
s: {proxy: cid for cid, proxy in d.items()} | ||
for s, d in self.callbacks.items()} | ||
|
||
def connect(self, s, func): | ||
@_api.rename_parameter("3.3.4", "s", "signal") | ||
def connect(self, signal, func): | ||
"""Register *func* to be called when signal *s* is generated.""" | ||
vallsv marked this conversation as resolved.
Show resolved
Hide resolved
vallsv marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self._func_cid_map.setdefault(s, {}) | ||
self._func_cid_map.setdefault(signal, {}) | ||
proxy = _weak_or_strong_ref(func, self._remove_proxy) | ||
if proxy in self._func_cid_map[s]: | ||
return self._func_cid_map[s][proxy] | ||
if proxy in self._func_cid_map[signal]: | ||
return self._func_cid_map[signal][proxy] | ||
cid = next(self._cid_gen) | ||
self._func_cid_map[s][proxy] = cid | ||
self.callbacks.setdefault(s, {}) | ||
self.callbacks[s][cid] = proxy | ||
self._func_cid_map[signal][proxy] = cid | ||
self.callbacks.setdefault(signal, {}) | ||
self.callbacks[signal][cid] = proxy | ||
return cid | ||
|
||
# Keep a reference to sys.is_finalizing, as sys may have been cleared out | ||
|
@@ -215,32 +216,43 @@ def _remove_proxy(self, proxy, *, _is_finalizing=sys.is_finalizing): | |
if _is_finalizing(): | ||
# Weakrefs can't be properly torn down at that point anymore. | ||
return | ||
for signal, proxies in list(self._func_cid_map.items()): | ||
try: | ||
del self.callbacks[signal][proxies[proxy]] | ||
except KeyError: | ||
pass | ||
if len(self.callbacks[signal]) == 0: | ||
del self.callbacks[signal] | ||
del self._func_cid_map[signal] | ||
for signal, proxy_to_cid in list(self._func_cid_map.items()): | ||
cid = proxy_to_cid.pop(proxy, None) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To check my understanding, The change on L221 and L241 are the critical changes in this PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. And i have just apply the same pattern to the disconnect. |
||
if cid is not None: | ||
del self.callbacks[signal][cid] | ||
break | ||
else: | ||
# Not found | ||
return | ||
# Clean up empty dicts | ||
if len(self.callbacks[signal]) == 0: | ||
del self.callbacks[signal] | ||
del self._func_cid_map[signal] | ||
|
||
def disconnect(self, cid): | ||
""" | ||
Disconnect the callback registered with callback id *cid*. | ||
|
||
No error is raised if such a callback does not exist. | ||
""" | ||
for eventname, callbackd in list(self.callbacks.items()): | ||
try: | ||
del callbackd[cid] | ||
except KeyError: | ||
continue | ||
else: | ||
for signal, functions in list(self._func_cid_map.items()): | ||
for function, value in list(functions.items()): | ||
if value == cid: | ||
del functions[function] | ||
return | ||
# Clean up callbacks | ||
for signal, cid_to_proxy in list(self.callbacks.items()): | ||
proxy = cid_to_proxy.pop(cid, None) | ||
if proxy is not None: | ||
break | ||
else: | ||
# Not found | ||
return | ||
|
||
proxy_to_cid = self._func_cid_map[signal] | ||
for current_proxy, current_cid in list(proxy_to_cid.items()): | ||
if current_cid == cid: | ||
assert proxy is current_proxy | ||
del proxy_to_cid[current_proxy] | ||
# Clean up empty dicts | ||
if len(self.callbacks[signal]) == 0: | ||
del self.callbacks[signal] | ||
del self._func_cid_map[signal] | ||
|
||
def process(self, s, *args, **kwargs): | ||
""" | ||
|
Uh oh!
There was an error while loading. Please reload this page.