From f1df1639a586c038652d4ef8bcf311dab728f936 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Thu, 7 Sep 2023 21:06:44 -0700 Subject: [PATCH] Avoid creating ref cycles This won't meaningfully affect most users, so I won't feel bad if this is closed :-) It's often important for performance to control when garbage collection runs and to reduce the need to run garbage collection in the first place. During AbstractionConnection.on_connect, it's common to raise and catch ResponseError, since e.g. CLIENT SETINFO is very new. However, because response is in a local, it creates ref cycles that keep all locals in all calling stack frames alive. The use of a local to store the exception is unfortunate, since exceptions hold references to their tracebacks, which hold references to the relevant frames, which holds a reference to the local exception. See https://peps.python.org/pep-0344/#open-issue-garbage-collection and https://peps.python.org/pep-3110/#rationale This breaks the cycle by deleting the local when we raise, so frames are destroyed by the normal reference counting mechanism. --- redis/connection.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/redis/connection.py b/redis/connection.py index 00d293a238..c6a22aae76 100644 --- a/redis/connection.py +++ b/redis/connection.py @@ -513,7 +513,10 @@ def read_response( self.next_health_check = time() + self.health_check_interval if isinstance(response, ResponseError): - raise response + try: + raise response + finally: + del response # avoid creating ref cycles return response def pack_command(self, *args):