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.
"finished without waiting for callbacks %r" %
self.pending_callbacks)
self.deactivate_stack_context()
+ self.deactivate_stack_context = None
return
except Exception:
self.finished = True
return self.exception_handler(type, value, traceback)
finally:
_state.contexts = self.old_contexts
+ self.old_contexts = None
class NullContext(object):
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