1. 程式人生 > >python記憶體監控工具memory_profiler和guppy的用法

python記憶體監控工具memory_profiler和guppy的用法

python2.7在記憶體管理上相比python3還是有些坑的,其釋放後的記憶體仍然保留在python的記憶體池中,不被系統所用。python迴圈引用的變數不會被回收,這會導致程式越執行,佔用的記憶體越大。我在跑py-faster-rcnn的demo時,基本上跑2000張影象,16g記憶體就要爆了。於是嘗試用python的記憶體監控工具來除錯程式,找到不能膨脹的變數,然後del之,再手動回收記憶體gc.collec()

下面是我用的兩個記憶體監視工具,一個是按每行程式碼檢視記憶體佔用的工具memory_profiler,一個是檢視佔用記憶體前十位變數的工具guppy。

1. memory_profiler

首先是安裝:

pip install -U memory_profiler

然後用profile修飾想要檢視的函式名:如:

@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a

if __name__ == '__main__':
    my_func()

輸出結果:

Line #    Mem usage  Increment   Line Contents
==============================================
     3                           @profile
     4      5.97 MB    0.00 MB   def my_func():
     5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
     6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
     7     13.61 MB -152.59 MB       del b
     8     13.61 MB    0.00 MB       return a
memory_profiler功能強大,更多功能可以看官網這裡

2. guppy

首先安裝:

pip install guppy

然後import下

from guppy import hpy
hxx = hpy()
heap = hxx.heap()
byrcs = hxx.heap().byrcs; 

在主程式下增加:

print(heap)

輸出示例:

Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  10124  22 81944416  95  81944416  95 list
     1  16056  34  1325464   2  83269880  96 str
     2   9147  20   745616   1  84015496  97 tuple
     3    102   0   366480   0  84381976  98 dict of module
     4    287   1   313448   0  84695424  98 dict of type
     5   2426   5   310528   0  85005952  98 types.CodeType
     6   2364   5   283680   0  85289632  99 function
     7    287   1   256960   0  85546592  99 type
     8    169   0   192088   0  85738680  99 dict (no owner)
     9    123   0   142728   0  85881408  99 dict of class

可以看到第一個list佔了95%的記憶體,若print(heap)在主程式的迴圈中,可以檢視每次迴圈後的變數記憶體佔用情況。

輸入以下命令,檢視這個佔記憶體最大的list中的資料型別:

byrcs[0].byid

最後測試後發現,test.py下get_im_blob等函式佔用記憶體不斷增大,每檢測一副影象,該函式增加6-10MB記憶體開銷。但奇怪的是用guppy檢視前十個變數,並沒有發現哪個變數有明顯的記憶體增大跡象。於是猜測可能是每張影象推理後,推理的結果bbox,label,img等資料儲存在了記憶體中,這樣方便所有影象推理結束後,plt.show().於是修改程式,每張影象推理後,plt.show()一下。用memory_profiler發現記憶體不再繼續增大,interesting!其實把plt.show()改成plt.close()也可以防止記憶體不斷增大。具體原因肯定是python 的記憶體回收機制規則導致的。