溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

對python程序內存泄漏調試的記錄

發布時間:2020-08-26 19:46:14 來源:腳本之家 閱讀:380 作者:ybdesire 欄目:開發技術

問題描述

調試python程序時,用下面這段代碼,可以獲得進程占用系統內存值。程序跑一段時間后,就能畫出進程對內存的占用情況。

def memory_usage_psutil():
 # return the memory usage in MB
 import psutil,os
 process = psutil.Process(os.getpid())
 mem = process.memory_info()[0] / float(2 ** 20)
 return mem

發現進程的內存占用一直再上漲,而這從邏輯上來說是不正常的,所以想到程序可能發生了Memory Leak。

python程序的Mem Leak

python程序不可能像C/C++一樣出現malloc了的內存沒有free這樣的Memory Leak。但也會遇到“邏輯上沒free”的情況,如下代碼所示。

def foo(a=[]):
 a.append(time.time())
 return a

參數a這樣可迭代的對象,稍不注意,它就能增長的很快。說白了,python的Memory Leak,就是“進程占用的內存莫名其妙一直再升高”。進程占用內存一直升高,與邏輯預期不一致,就可能發生了Memory Leak。

以下面程序為例說明Memory Leak調試的過程:

def memory_usage_psutil():
 # return the memory usage in MB
 import psutil,os
 process = psutil.Process(os.getpid())
 mem = process.memory_info()[0] / float(2 ** 20)
 return mem

def get_current_obj(a=[]):
 a.append([0]*1000)
 return a

def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 if(i%100==0):
  print(memory_usage_psutil())

if __name__=='__main__':
 main()

調試過程

用pmap -x [pid]查看進程占用的堆內存大小

首先想到,會不會是上面用的memory_usage_psutil函數統計錯誤呢。

先運行程序,再用pmap查看,發現進程內存占用確實很高。多次執行該命令,也可以發現內存一直升高。

對python程序內存泄漏調試的記錄

強制執行GC(gc.collect())

在需要執行GC的地方加上gc.collect()

def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 import gc;gc.collect()
 if(i%100==0):
  print(memory_usage_psutil())

可以看到,強制GC后,程序執行變慢,但內存依然不斷升高。

使用memory_profiler查看

安裝memory_profiler

pip install -U memory_profiler

用@profile修飾需要查看內存的函數

@profile
def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 if(i%100==0):
  print(memory_usage_psutil())

用如下命令運行程序

python -m memory_profiler main.py

可以看到程序執行完成后,輸出結果如下

Line # Mem usage Increment Line Contents
================================================
 12 28.570 MiB 0.000 MiB @profile
 13    def main():
 14 28.570 MiB 0.000 MiB obj = []
 15 106.203 MiB 77.633 MiB for i in range(10000):
 16 106.203 MiB 0.000 MiB  obj = get_current_obj(obj)
 17 106.203 MiB 0.000 MiB  if(i%100==0):
 18 105.445 MiB -0.758 MiB  print(memory_usage_psutil())

這樣就能看到導致內存上漲最快的那幾行代碼。

用guppy查看python對象占用的堆內存大小

將main修改如下,即可查看python對堆內存的占用量。

def main(): 
 obj = []
 for i in range(10000):
 obj = get_current_obj(obj)
 if(i%100==0):
  print(memory_usage_psutil())
  from guppy import hpy;hxx = hpy();heap = hxx.heap()
  print(heap)

下面就是輸出結果,python程序中各個對象對內存的占用從大到小排列。

 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

可以從結果中看到,95%的進程內存,都被一個list占用。

還可以通過下面這種方式,查看這個占內存最大的list中的數據類型。

from guppy import hpy;hxx = hpy();byrcs = hxx.heap().byrcs; byrcs[0].byid

關于guppy的詳細用法,可以看這里(http://smira.ru/wp-content/uploads/2011/08/heapy.html)。

以上這篇對python程序內存泄漏調試的記錄就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女