
This is a huge improvement to the way I use Firefox.
func_globals
dictionary points to that of the main copy, rather than the new copy.Command
class. However, as there are now multiple namespace locations where commands may be located, I decided to try an alternate approach. Instead I would find use the garbage collector to find all the subclasses of the Command
class, and obtain the commands that way.for class_ in pysupport.FindSubclasses(Command, inclusive=True):Each time I modified the rehash command, I started to see a ghost class appearing in the output of this logging action. So for the umpteenth time, I wrote some code to dig through the referrers in the garbage collector, in order to work out what was holding the references.
for verb in class_.__verbs__:
if verb in self.verbs:
logger.warning("Duplicate '%s': %s", verb, class_)
continue
5 REFERRERS FOR <type 'classobj'> __builtin__.Rehash 0x20a84b0I've trimmed some redundant information out by hand. But what it shows, is that the class has a function that has a dictionary, that has a reference to the class. Seeing what the contents of the trimmed containers were, it indicates that the normal
SKIPPED/is-local-frame 0x20ebec8 <frame object at 0x020EBEC8>
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x20f7ae0 <frame object at 0x020F7AE0>
6 REFERRERS FOR <type 'list'> [ ... ] 0x20ae1e8
5 REFERRERS FOR <type 'listiterator'> 0x1c33110
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x1b1fc88 <frame object at 0x01B1FC88>
SKIPPED/is-referrer-list 0x20a9c10 <type 'list'>
SKIPPED/is-local-frame 0x1b1fe30 <frame object at 0x01B1FE30>
SKIPPED/is-local-frame 0x20f7ae0 <frame object at 0x020F7AE0>
SKIPPED/is-local-frame 0x20ebec8 <frame object at 0x020EBEC8>
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-referrer-list 0x20a96c0 <type 'list'>
SKIPPED/is-local-frame 0x1b1fc88 <frame object at 0x01B1FC88>
SKIPPED/is-local-frame 0x20f7ae0 <frame object at 0x020F7AE0>
5 REFERRERS FOR <type 'dict'> { ... } 0x20aba50
SKIPPED/is-local-frame 0x20ebec8 <frame object at 0x020EBEC8>
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-referrer-list 0x20a96c0 <type 'list'>
SKIPPED/is-local-frame 0x20cc188 <frame object at 0x020CC188>
5 REFERRERS FOR <type 'function'> 0x20a5eb0
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x20cc188 <frame object at 0x020CC188>
SKIPPED/is-referrer-list 0x20a9490 <type 'list'>
SKIPPED/is-local-frame 0x20cc330 <frame object at 0x020CC330>
5 REFERRERS FOR <type 'dict'> { ... } 0x20ab9c0
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x20cc330 <frame object at 0x020CC330>
SKIPPED/is-referrer-list 0x20a9ad0 <type 'list'>
SKIPPED/is-local-frame 0x20cf078 <frame object at 0x020CF078>
SKIPPED/seen 0x20a84b0 __builtin__.Rehash
func_globals
reference is creating a circular reference and keeping the class alive.class AClass:And then repeatedly reloaded the class in the interpreter..
def AFunction(self):
pass
>>> d = {}So outside of my framework Python does the correct thing.
>>> execfile("test.py", d, d)
>>> d = {}
>>> execfile("test.py", d, d)
>>> d = {}
>>> execfile("test.py", d, d)
>>> d = {}
>>> execfile("test.py", d, d)
>>> import gc, types
>>> for v in gc.get_objects():
... if type(v) is types.ClassType and v.__name__ == "AClass":
... print v
...
__builtin__.AClass
__builtin__.AClass
__builtin__.AClass
__builtin__.AClass
>>> gc.collect()
12
>>> for v in gc.get_objects():
... if type(v) is types.ClassType and v.__name__ == "AClass":
... print v
...
__builtin__.AClass
execfile
is creating this circular reference in a way that is somehow different (not seeing it).