Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get more frames from backtrace in tracemalloc snapshot comparisons (python 3.6)?

Description of my question

I'm trying to chase down a memory leak in a python 3.6 program.

For that I'm testing tracemalloc, which allows me to compare memory snapshots and print out a "backtrace".

The max number of frames in the backtrace should be set as the first argument to tracemalloc.start(), according to the docs.

However, in my minimal test setup (code below) I start tracemalloc with argument 25, but I only get 1 frame in the backtrace, where I would expect 2:

What I got as output

me@my_machine:/tmp$ python ./test_tm.py 

Entry: /tmp/test_tm_utils.py:2: size=3533 KiB (+3533 KiB), count=99746 (+99746), average=36 B
Traceback:
  /tmp/test_tm_utils.py:2

What I expected as output

I would expect two lines, like so:

Entry: /tmp/test_tm_utils.py:2: size=3533 KiB (+3533 KiB), count=99746 (+99746), average=36 B
Traceback:
  /tmp/test_tm_utils.py:2
  /tmp/test_tm.py:10
  ^^^^^^^^^^^^^^^^^^

Minimal code sample

Main program in _/tmp/test_tm.py_:

import tracemalloc

tracemalloc.start(25)
import test_tm_utils


if __name__ == '__main__':

    s1 = tracemalloc.take_snapshot()
    test_tm_utils.myfun()

    s2 = tracemalloc.take_snapshot()

    diff = s2.compare_to(s1, 'lineno')

    for entry in diff[:1]:
        print('\nEntry: {}'.format(entry))
        print('Traceback:')
        for line in entry.traceback:
            print('  {}'.format(line))

And the memory leak function in test_tm_utils.py:

def myfun(lst=list()):
    lst.append([i for i in range(100000)])
like image 378
Ytsen de Boer Avatar asked Sep 14 '25 19:09

Ytsen de Boer


1 Answers

The secret is the key_type parameter. You must use the value "traceback" to get all the lines specified in tracemalloc.start(). If you use "lineno" or "filename" you only get one line.

This is true for both Statistics or in your case compare_to.

So your code should look something like this:

s2 = tracemalloc.take_snapshot()

diff = s2.compare_to(s1, 'traceback') # This is the only change

for entry in diff[:1]:
    print('\nEntry: {}'.format(entry))
    print('Traceback:')
    for line in entry.traceback:
        print('  {}'.format(line))
like image 130
Timothy Driscoll Avatar answered Sep 17 '25 19:09

Timothy Driscoll