python memory usage_python程序内存泄漏调试记录(转)

问题描述

调试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查看,发现进程内存占用确实很高。多次执行该命令,也可以发现内存一直升高。

强制执行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

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值