[Urwid] Bug: Signal module create backreferences

Dominic LoBue dominic.lobue at gmail.com
Thu Mar 4 14:55:56 EST 2010


While trying to figure out why my program is eating up so much ram I
discovered that objects that were supposed to be dead were still
alive. Much debugging later, I discovered that the problem was caused
by an object being kept alive by references to it by the
_urwid_signals attribute its children objects.

I am using the signal module in urwid to send messages from child to
parent objects. I use it this way extensively actually in order to
make my collapsible widgets work.

You can see a back-reference object graph that shows the problem here:

You can recreate the problem with the following code: <EOF
from urwid import MetaSignals, emit_signal, connect_signal

class my_other_object(object):
    __metaclass__ = MetaSignals
    signals = ['something']

    def do_emit(self):
        emit_signal(self, 'something')

class my_object(object):
    __metaclass__ = MetaSignals
    signals = ['something']

    def __init__(self):
        self.something = my_other_object()
        connect_signal(self.something, 'something', self.melse)

    def melse(self):
        print 'child phones home'

a = my_object()
del a


If you install objgraph (it's found in the cheeseshop), if you append
the next two lines to the bottom of the above script, you can see the
problem more graphically (only way I know how to find dead objects
that haven't been taken by the gc yet):
import objgraph
objgraph.show_backrefs(objgraph.by_type('my_object')[0], max_depth=10)

You can probably resolve this problem by using
weakref.WeakValueDictionary instead of a dict. Although personally I'd
prefer it if you switch back to having the signal registry in the
Signals class again (one big dict is smaller than thousands and
thousands of tiny ones).

Dominic LoBue

More information about the Urwid mailing list