A helper for analyzing PYTHONDUMPREFS output,,'''PYTHON SO


'''PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2--------------------------------------------1. This LICENSE AGREEMENT is between the Python Software Foundation('PSF'), and the Individual or Organization ('Licensee') accessing andotherwise using this software ('Python') in source or binary form andits associated documentation.2. Subject to the terms and conditions of this License Agreement, PSFhereby grants Licensee a nonexclusive, royalty-free, world-widelicense to reproduce, analyze, test, perform and/or display publicly,prepare derivative works, distribute, and otherwise use Pythonalone or in any derivative version, provided, however, that PSF'sLicense Agreement and PSF's notice of copyright, i.e., 'Copyright (c)2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved'are retained in Python alone or in any derivative version preparedby Licensee.3. In the event Licensee prepares a derivative work that is based onor incorporates Python or any part thereof, and wants to makethe derivative work available to others as provided herein, thenLicensee hereby agrees to include in any such work a brief summary ofthe changes made to Python.4. PSF is making Python available to Licensee on an 'AS IS'basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS ORIMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO ANDDISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESSFOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOTINFRINGE ANY THIRD PARTY RIGHTS.5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHONFOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS ASA RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.6. This License Agreement will automatically terminate upon a materialbreach of its terms and conditions.7. Nothing in this License Agreement shall be deemed to create anyrelationship of agency, partnership, or joint venture between PSF andLicensee.  This License Agreement does not grant permission to use PSFtrademarks or trade name in a trademark sense to endorse or promoteproducts or services of Licensee, or any third party.8. By copying, installing or otherwise using Python, Licenseeagrees to be bound by the terms and conditions of this LicenseAgreement.'''#! /usr/bin/env python'''combinerefs pathA helper for analyzing PYTHONDUMPREFS output.When the PYTHONDUMPREFS envar is set in a debug build, at Python shutdowntime Py_Finalize() prints the list of all live objects twice:  first itprints the repr() of each object while the interpreter is still fully intact.After cleaning up everything it can, it prints all remaining live objectsagain, but the second time just prints their addresses, refcounts, and typenames (because the interpreter has been torn down, calling repr methods atthis point can get into infinite loops or blow up).Save all this output into a file, then run this script passing the path tothat file.  The script finds both output chunks, combines them, then printsa line of output for each object still alive at the end:    address refcnt typename repraddress is the address of the object, in whatever format the platform Cproduces 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 PYTHONDUMPREFSoutput 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 theobjects 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 displaystrings 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 allocatedprinted 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 PYTHONDUMPREFSoutput blocks said there were 14 references to it.  This is probably due toC modules that intern the string '__len__' and keep a reference to it in afile static.    00857038 [46->5] tuple ()46-5 = 41 references to the empty tuple were removed by the cleanup actionsbetween the times PYTHONDUMPREFS produced output.    00858028 [1025->1456] str '<dummy key>'The string '<dummy key>', which is used in dictobject.c to overwrite a realkey that gets deleted, grew several hundred references during cleanup.  Itsuggests that stuff did get removed from dicts by cleanup, but that the dictsthemselves are staying alive for some reason. '''import reimport sys# Generate lines from fileiter.  If whilematch is true, continue reading# while the regexp object pat matches line.  If whilematch is false, lines# are read so long as pat doesn't match them.  In any case, the first line# that doesn't match pat (when whilematch is true), or that does match pat# (when whilematch is false), is lost, and fileiter will resume at the line# following it.def read(fileiter, pat, whilematch):    for line in fileiter:        if bool(pat.match(line)) == whilematch:            yield line        else:            breakdef combine(fname):    f = file(fname)    fi = iter(f)    for line in read(fi, re.compile(r'^Remaining objects:$'), False):        pass    crack = re.compile(r'([a-zA-Z\d]+) \[(\d+)\] (.*)')    addr2rc = {}    addr2guts = {}    before = 0    for line in read(fi, re.compile(r'^Remaining object addresses:$'), False):        m = crack.match(line)        if m:            addr, addr2rc[addr], addr2guts[addr] = m.groups()            before += 1        else:            print '??? skipped:', line    after = 0    for line in read(fi, crack, True):        after += 1        m = crack.match(line)        assert m        addr, rc, guts = m.groups() # guts is type name here        if addr not in addr2rc:            print '??? new object created while tearing down:', line.rstrip()            continue        print addr,        if rc == addr2rc[addr]:            print '[%s]' % rc,        else:            print '[%s->%s]' % (addr2rc[addr], rc),        print guts, addr2guts[addr]    f.close()    print '%d objects before, %d after' % (before, after)if __name__ == '__main__':    combine(sys.argv[1])

评论关闭