Search for memory leaks in a tornado project

Guppy doesn't work with Python 3 (for February 2015).

requirements.txt:

guppy

Use MemoryHandler to inspect memory usage:

from guppy import hpy
from tornado import web, ioloop, gen, options


class LeakObject(object):

    def __init__(self):
        self.a = {}
        for i in xrange(1000):
            self.a[i] = 'leak' * 1000

    def __del__(self):
        pass


class LeakHandler(web.RequestHandler):

    def get(self):
        # create memory leak
        obj1 = LeakObject()
        obj2 = LeakObject()
        obj1.leak = obj2
        obj2.leak = obj1
        self.write('Leak')


class MemoryHandler(web.RequestHandler):

    def get(self):
        h = hpy()
        r = h.heap()
        self.write('<pre>')
        self.write(unicode(r))
        r = r.more
        self.write(unicode(r))
        r = r.more
        self.write(unicode(r))
        self.write('</pre>')


application = web.Application([
    (r'/leak', LeakHandler),
    (r'/memory', MemoryHandler),
], debug=True)


if __name__ == "__main__":
    options.parse_command_line()
    application.listen(5000)
    ioloop.IOLoop.instance().start()
nanvel-air:leaks nanvel$ curl http://localhost:5000/leak
Leak
...
nanvel-air:leaks nanvel$ curl http://localhost:5000/memory
<pre>
Partition of a set of 153822 objects. Total size = 206002744 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  83492  54 197180696  96 197180696  96 str
     1    341   0  2958200   1 200138896  97 dict (no owner)
     2  15243  10  1287768   1 201426664  98 tuple
     3  37662  24   903888   0 202330552  98 int
     4    202   0   652528   0 202983080  99 dict of module
     5   4172   3   534016   0 203517096  99 types.CodeType
     6   3994   3   479280   0 203996376  99 function
     7    493   0   457528   0 204453904  99 dict of type
     8    493   0   442384   0 204896288  99 type
     9    201   0   199128   0 205095416 100 dict of class
<188 more rows. Type e.g. '_.more' to view.> Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
    10    426   0   100816   0 205196232 100 list
    11   1187   1    94960   0 205291192 100 __builtin__.wrapper_descriptor
    12    844   1    74272   0 205365464 100 __builtin__.weakref
    13    885   1    63720   0 205429184 100 types.BuiltinFunctionType
    14    698   0    50256   0 205479440 100 __builtin__.method_descriptor
    15    178   0    41296   0 205520736 100 __builtin__.set
    16     19   0    40648   0 205561384 100 dict of email.LazyImporter
    17    585   0    34808   0 205596192 100 unicode
    18     26   0    31856   0 205628048 100 dict of abc.ABCMeta
    19     68   0    30024   0 205658072 100 _sre.SRE_Pattern
<178 more rows. Type e.g. '_.more' to view.> Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
    20     96   0    26880   0 205684952 100 dict of function
    21    355   0    25560   0 205710512 100 types.GetSetDescriptorType
    22     26   0    23504   0 205734016 100 abc.ABCMeta
    23     78   0    21840   0 205755856 100 dict of _weakrefset.WeakSet
    24    201   0    20904   0 205776760 100 class
    25    255   0    18360   0 205795120 100 types.MemberDescriptorType
>   26     48   0    13440   0 205808560 100 dict of __main__.LeakObject
    27    138   0    12144   0 205820704 100 __builtin__.property
    28     22   0    11536   0 205832240 100 dict of guppy.etc.Glue.Interface
    29    202   0    11312   0 205843552 100 module
<168 more rows. Type e.g. '_.more' to view.></pre>

UPD: 2017-06-29

Another tool: memory_profiler. Supports Python3.

Licensed under CC BY-SA 3.0