Python:内存泄漏调试
我有一个在Django中运行的小脚本,它是多线程的。随着时间的推移,它开始占用越来越多的内存。放着它一天,内存就会吃掉大约6GB,导致我开始使用交换空间。
根据这个链接 http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks,我发现这是一种最常见的情况(当时只用了800M的内存):
(Pdb) objgraph.show_most_common_types(limit=20)
dict 43065
tuple 28274
function 7335
list 6157
NavigableString 3479
instance 2454
cell 1256
weakref 974
wrapper_descriptor 836
builtin_function_or_method 766
type 742
getset_descriptor 562
module 423
method_descriptor 373
classobj 256
instancemethod 255
member_descriptor 218
property 185
Comment 183
__proxy__ 155
但是没有发现什么奇怪的地方。那我现在该怎么做才能帮助调试内存问题呢?
更新:我尝试了一些大家推荐的方法。我让程序运行了一整夜,早上醒来时,内存使用量达到了50% * 8G = 4G。
(Pdb) from pympler import muppy
(Pdb) muppy.print_summary()
types | # objects | total size
========================================== | =========== | ============
unicode | 210997 | 97.64 MB
list | 1547 | 88.29 MB
dict | 41630 | 13.21 MB
set | 50 | 8.02 MB
str | 109360 | 7.11 MB
tuple | 27898 | 2.29 MB
code | 6907 | 1.16 MB
type | 760 | 653.12 KB
weakref | 1014 | 87.14 KB
int | 3552 | 83.25 KB
function (__wrapper__) | 702 | 82.27 KB
wrapper_descriptor | 998 | 77.97 KB
cell | 1357 | 74.21 KB
<class 'pympler.asizeof.asizeof._Claskey | 1113 | 69.56 KB
function (__init__) | 574 | 67.27 KB
但是这些数字加起来并不等于4G,也没有给我提供什么有用的数据结构去修复。这个unicode是来自一个“完成”节点的集合,而列表看起来只是一些随机的weakref
。
我没有使用guppy,因为它需要一个C扩展,而我没有管理员权限,所以构建起来会很麻烦。
我使用的对象都没有__del__
方法,查看了一下库,似乎Django和python-mysqldb也没有。还有其他的建议吗?
7 个回答
可以看看Ned Batchelder写的这篇很棒的博客,里面讲了他们是如何找到HP的Tabblo中真正的内存泄漏问题的。这是一个经典案例,值得一读。
在settings.py文件中,DEBUG设置为False吗?
如果没有设置为False,Django会很乐意地记录你所有的SQL查询,这样会占用很多空间。
可以参考这个链接:http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/。简单来说,如果你在使用Django,但不是通过网页请求的方式运行,那么你需要手动执行 db.reset_queries()
(当然,像其他人提到的那样,确保DEBUG=False)。Django在处理网页请求后会自动执行 reset_queries()
,但在你这种运行方式下,这个操作是不会自动进行的。