From: Ben Darnell Date: Sat, 17 Nov 2012 21:35:42 +0000 (-0500) Subject: Fix a memory leak in stack_context. X-Git-Tag: v3.0.0~223 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bff07405549a6eb173a4cfc9bbc3fc7c6da5cdd7;p=thirdparty%2Ftornado.git Fix a memory leak in stack_context. The old_contexts reference in StackContexts could maintain a chain of old irrelevant contexts, so clear it once it's no longer needed. This was mainly a problem in gen.engine, where additional contexts would accumulate in memory (but not on the stack) for each asynchronous operation. Also clear the deactivate_stack_context in gen.Runner to allow the StackContext to be garbage-collected sooner. --- diff --git a/tornado/gen.py b/tornado/gen.py index 51d64a3aa..88ded2eff 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -374,6 +374,7 @@ class Runner(object): "finished without waiting for callbacks %r" % self.pending_callbacks) self.deactivate_stack_context() + self.deactivate_stack_context = None return except Exception: self.finished = True diff --git a/tornado/stack_context.py b/tornado/stack_context.py index b0bf108ac..d4aec3c5e 100644 --- a/tornado/stack_context.py +++ b/tornado/stack_context.py @@ -160,6 +160,7 @@ class ExceptionStackContext(object): return self.exception_handler(type, value, traceback) finally: _state.contexts = self.old_contexts + self.old_contexts = None class NullContext(object): diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py index 6c674c5ad..b25d1050f 100644 --- a/tornado/test/gen_test.py +++ b/tornado/test/gen_test.py @@ -270,6 +270,28 @@ class GenTest(AsyncTestCase): initial_stack_depth = len(stack_context._state.contexts) self.run_gen(outer) + def test_stack_context_leak_exception(self): + # same as previous, but with a function that exits with an exception + from tornado import stack_context + + @gen.engine + def inner(callback): + yield gen.Task(self.io_loop.add_callback) + 1 / 0 + + @gen.engine + def outer(): + for i in xrange(10): + try: + yield gen.Task(inner) + except ZeroDivisionError: + pass + stack_increase = len(stack_context._state.contexts) - initial_stack_depth + self.assertTrue(stack_increase <= 2) + self.stop() + initial_stack_depth = len(stack_context._state.contexts) + self.run_gen(outer) + class GenSequenceHandler(RequestHandler): @asynchronous