如何調試Python 程序的內存泄露問題
如果大家在 Linux 或者 macOS 下面運行一段可能導致內存泄露的程序,那么你可能會看到下面這樣的情況:
而如果你用的系統是 Windows,那么可能電腦直接就卡死了。
但是,調試這種 OOM(Out of Memory)的問題有時候是非常困難的,因為你不知道代碼哪個地方會導致內存泄露。但是如果你運行程序進行調試,程序又會中途被殺掉或者直接卡死系統。
如果我們有辦法看到程序里面每一個函數占用的內存大小,那么我們就能縮小檢查的范圍。
為了實現這個目的,我們可以安裝并使用一個叫做filprofiler的第三方庫,它可以分析 Python 程序的內存占用情況。
我們先安裝這個庫:
- pip install filprofiler
然后寫一段會導致內存泄露的代碼:
- def func_a():
- print('我是一個正常的函數')
- def func_b():
- print('我是第二個正常的函數')
- def func_b():
- print('我是第三個正常的函數')
- def func_oom():
- print('我是一個會導致內存泄露的函數')
- datas = []
- while True:
- datas.append('s' * 1024 * 1024)
- print('運行程序的時候,你不會看到這一行')
- def run():
- func_a()
- func_b()
- func_oom()
- run()
這段程序直接運行會因為內存泄露的問題被系統直接殺死。
在使用filprofiler之前,還需要調整一下虛擬內存的大小。否則,filprofiler本身也會因為占用內存過大的問題而被系統殺掉。
先使用free命令看一下系統可用的內存有多少:
系統可用內存為1619456 KB
我們使用ulimit命令,把程序能夠使用的內存稍稍調低一些,這樣即使被占滿,也不會被系統殺死:
- ulimit -Sv 1600000
然后,使用 filprofiler 來運行這個程序:
- fil-profile run test.py
運行效果如下圖所示:
filprofiler 會在當前文件夾下面生成一個fil-result文件夾,在里面會有一個以時間命名的文件夾,文件夾中會有兩個svg文件,如下圖所示:
我們使用瀏覽器打開其中的out-of-memory.svg文件,可以看到如下圖所示的內存占用圖:
從圖中可以看到,占用內存最大的函數是func_oom,程序也是在這個地方崩潰的。