From 13e2decc392608df53b891937ca4d98d1f0b9993 Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Wed, 4 Jul 2018 07:24:58 +0200 Subject: [PATCH 1/2] Bug #47114: Fix memory leak - __del__ The Python garbage collector (GC) nowadays can free cyclic structure, but only if that cycle does NOT contain objects implementing the `__del__` method, as the GC then cannot decide which object to free first: That method is only called *after* the GC has decided to free the object and then it is pointless to clean the exception data. Remove the `__del__` method. --- notifier/threads.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/notifier/threads.py b/notifier/threads.py index 2aebcf4..19992de 100644 --- a/notifier/threads.py +++ b/notifier/threads.py @@ -66,10 +66,6 @@ def __init__( self, name, function, callback ): notifier.dispatcher_add( _simple_threads_dispatcher ) _threads.append( self ) - def __del__( self ): - if self._exc_info is not None: - del self._exc_info - def run( self ): """Starts the thread""" self._thread.start() From 7715a44c752606e1a3ea5afd270237310bb60251 Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Wed, 4 Jul 2018 07:28:55 +0200 Subject: [PATCH 2/2] Bug #47114: Fix memory leak - traceback The Python garbage collector (GC) nowadays can free cyclic structure, but keeping a Traceback object is still considered a bad idea: It contains a reference to all stack frames, which reference all local variables, and thus the traceback itself. Format the traceback once and replace the reference with None. The standard traceback library handles this fine. --- notifier/threads.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/notifier/threads.py b/notifier/threads.py index 19992de..97cfe85 100644 --- a/notifier/threads.py +++ b/notifier/threads.py @@ -79,8 +79,12 @@ def _run( self ): trace = None exc_info = None except BaseException as exc: - exc_info = sys.exc_info() - trace = traceback.format_tb( sys.exc_info()[ 2 ] ) + try: + etype, value, tb = sys.exc_info() + trace = traceback.format_tb(tb) + exc_info = (etype, value, None) + finally: + etype = value = tb = None result = exc self.lock() try: