排查python内存泄露中几个工具的使用

本文主要介绍3个工具:pdb,objgraph,以及pympler。

1.pdb

pdb是专门用于python代码调试,模仿gdb。
使用pdb可以查看堆栈,打印变量等。

这里介绍的是命令行下的pdb。
命令行下使用pdb,代码侵入小,调试方便。

本例中,python安装在当前目录下.venv

使用pdb加载python程序

.venv/bin/python -m pdb  orange.py
> /Users/lanyang/workspace/orange/orange.py(3)()
-> import inspect
(Pdb)

启动程序

(Pdb)c

这样,python代码就开始执行了。

相关的命令有

  • bt 打印堆栈
  • q 退出
  • pp 打印变量
  • c(ont(inue)) 继续执行

更多命令可参考:

(Pdb) help

Documented commands (type help ):
========================================
EOF    c          d        h         list      q        rv       undisplay
a      cl         debug    help      ll        quit     s        unt
alias  clear      disable  ignore    longlist  r        source   until
args   commands   display  interact  n         restart  step     up
b      condition  down     j         next      return   tbreak   w
break  cont       enable   jump      p         retval   u        whatis
bt     continue   exit     l         pp        run      unalias  where

Miscellaneous help topics:
==========================
exec  pdb

2.objgraph

安装objgraph

pip install objgraph

查看最常用的类型

(Pdb) import objgraph
(Pdb) objgraph.show_most_common_types(limit=20)
function                   22750
dict                       15520
tuple                      12536
weakref                    6679
list                       5516
type                       3449
getset_descriptor          3408
cell                       2566
set                        2496
ModuleSpec                 1588
module                     1582
SourceFileLoader           1502
wrapper_descriptor         1332
builtin_function_or_method 1241
method_descriptor          1219
property                   1171
member_descriptor          822
classmethod                697
WeakSet                    571
MovedAttribute             501

感觉这个函数没什么用。

查看增长最快的类型

(Pdb) objgraph.show_growth(limit=10)
function             22749    +22749
dict                 15515    +15515
tuple                12332    +12332
weakref               6680     +6680
list                  5517     +5517
type                  3449     +3449
getset_descriptor     3408     +3408
cell                  2565     +2565
set                   2496     +2496
ModuleSpec            1588     +1588

show_growth()打印两次调用之间增加的类型。如果这其中有自己定义的类型,很可能就是问题所在。如果都是python内置类型,可能要花费更多功夫了。

一般排查问题时,在程序开始执行时,调用show_growth(),程序跑一段时间后,再次调用show_growth(),查看哪些对象增长最快。

如果使用pdb在命令行下调试,ctrl+c停止程序的时候,注意观察上下文,保证跟上次import objgraph时一样,否则,会出现:

(Pdb) objgraph.show_growth(limit=10)
*** NameError: name 'objgraph' is not defined
(Pdb)

如果出现这个问题,可以继续让程序执行,再ctrl+c停止程序。

查看某个类型

(Pdb) objgraph.by_type('list')

这个可能会打印一堆。

3.pympler

使用objgraph时,虽然可以看到增长最快的对象,但是无法得知占用内存最多的是哪个。

下面我们就使用pympler,查看内存占用。

(Pdb) from pympler import tracker
(Pdb) tr = tracker.SummaryTracker()
(Pdb) tr.print_diff()
                  types |   # objects |   total size
======================= | =========== | ============
           

tracker对象初始化的时候会创建一个summary,每次调用tracker.print_diff()的时候又会创建一个summary,当前的summary与上次的summary做比较,并打印两者之间的不同。

4.参考

pdb

objgraph

pympler

pympler muppy

Python内存泄露调试指导思想

使用gc、objgraph干掉python内存泄露与循环引用!

python 进程内存增长问题, 解决方法和工具

你可能感兴趣的:(python)