排查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)<module>()
-> import inspect
(Pdb)

啟動程序

(Pdb)c

這樣,python代碼就開始執行了。

相關的命令有

  • bt 打印堆棧
  • q 退出
  • pp 打印變量
  • c(ont(inue)) 繼續執行

更多命令可參考:

(Pdb) help

Documented commands (type help <topic>):
========================================
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
======================= | =========== | ============
           <class 'list |       12769 |      1.18 MB
            <class 'str |       12769 |    950.47 KB
            <class 'int |        2513 |     68.71 KB
           <class 'code |           1 |    144     B
  function (store_info) |           1 |    136     B
           <class 'cell |           2 |     96     B
          <class 'tuple |           1 |     64     B
         <class 'method |          -1 |    -64     B
           <class 'dict |           0 |   -128     B
(Pdb) tr.print_diff()
         types |   # objects |   total size
============== | =========== | ============
  <class 'list |           1 |     88     B
   <class 'str |           1 |     70     B
(Pdb) tr.print_diff()
  types |   # objects |   total size
======= | =========== | ============
(Pdb)

tracker對象初始化的時候會創建一個summary,每次調用tracker.print_diff()的時候又會創建一個summary,當前的summary與上次的summary做比較,並打印兩者之間的不同。

4.參考

pdb

objgraph

pympler

pympler muppy

Python內存泄露調試指導思想

使用gc、objgraph干掉python內存泄露與循環引用!

python 進程內存增長問題, 解決方法和工具


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM