ó x”ŝfc@sTdZddlZddlZd„Zd„ZedkrPeejdƒndS(sL combinerefs path A helper for analyzing PYTHONDUMPREFS output. When the PYTHONDUMPREFS envar is set in a debug build, at Python shutdown time Py_Finalize() prints the list of all live objects twice: first it prints the repr() of each object while the interpreter is still fully intact. After cleaning up everything it can, it prints all remaining live objects again, but the second time just prints their addresses, refcounts, and type names (because the interpreter has been torn down, calling repr methods at this point can get into infinite loops or blow up). Save all this output into a file, then run this script passing the path to that file. The script finds both output chunks, combines them, then prints a line of output for each object still alive at the end: address refcnt typename repr address is the address of the object, in whatever format the platform C produces for a %p format code. refcnt is of the form "[" ref "]" when the object's refcount is the same in both PYTHONDUMPREFS output blocks, or "[" ref_before "->" ref_after "]" if the refcount changed. typename is object->ob_type->tp_name, extracted from the second PYTHONDUMPREFS output block. repr is repr(object), extracted from the first PYTHONDUMPREFS output block. CAUTION: If object is a container type, it may not actually contain all the objects shown in the repr: the repr was captured from the first output block, and some of the containees may have been released since then. For example, it's common for the line showing the dict of interned strings to display strings that no longer exist at the end of Py_Finalize; this can be recognized (albeit painfully) because such containees don't have a line of their own. The objects are listed in allocation order, with most-recently allocated printed first, and the first object allocated printed last. Simple examples: 00857060 [14] str '__len__' The str object '__len__' is alive at shutdown time, and both PYTHONDUMPREFS output blocks said there were 14 references to it. This is probably due to C modules that intern the string "__len__" and keep a reference to it in a file static. 00857038 [46->5] tuple () 46-5 = 41 references to the empty tuple were removed by the cleanup actions between the times PYTHONDUMPREFS produced output. 00858028 [1025->1456] str '' The string '', which is used in dictobject.c to overwrite a real key that gets deleted, grew several hundred references during cleanup. It suggests that stuff did get removed from dicts by cleanup, but that the dicts themselves are staying alive for some reason. i˙˙˙˙Nccs9x2|D]*}t|j|ƒƒ|kr0|VqPqWdS(N(tbooltmatch(tfileitertpatt whilematchtline((s1/usr/lib64/python2.7/Tools/scripts/combinerefs.pytreadQs c CsĤt|ƒ}t|ƒ}x#t|tjdƒtƒD]}q4Wtjdƒ}i}i}d}xkt|tjdƒtƒD]N}|j|ƒ}|rÀ|jƒ\} || <|| <|d7}q{dG|GHq{Wd} x³t||tƒD]Ÿ}| d7} |j|ƒ}|st ‚|jƒ\} } } | |krGdG|j ƒGHqĉn| G| || krfd| Gnd || | fG| G|| GHqĉW|j ƒd || fGHdS( Ns^Remaining objects:$s([a-zA-Z\d]+) \[(\d+)\] (.*)is^Remaining object addresses:$is ??? skipped:s*??? new object created while tearing down:s[%s]s[%s->%s]s%d objects before, %d after( tfiletiterRtretcompiletFalseRtgroupstTruetAssertionErrortrstriptclose( tfnametftfiRtcracktaddr2rct addr2gutstbeforetmtaddrtaftertrctguts((s1/usr/lib64/python2.7/Tools/scripts/combinerefs.pytcombineXs<  ""       t__main__i(t__doc__R tsysRRt__name__targv(((s1/usr/lib64/python2.7/Tools/scripts/combinerefs.pytFs     &