Python:内存泄漏调试

29 投票
7 回答
23414 浏览
提问于 2025-04-15 13:54

我有一个在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 个回答

6

可以看看Ned Batchelder写的这篇很棒的博客,里面讲了他们是如何找到HP的Tabblo中真正的内存泄漏问题的。这是一个经典案例,值得一读。

21

在settings.py文件中,DEBUG设置为False吗?

如果没有设置为False,Django会很乐意地记录你所有的SQL查询,这样会占用很多空间。

32

可以参考这个链接:http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/。简单来说,如果你在使用Django,但不是通过网页请求的方式运行,那么你需要手动执行 db.reset_queries()(当然,像其他人提到的那样,确保DEBUG=False)。Django在处理网页请求后会自动执行 reset_queries(),但在你这种运行方式下,这个操作是不会自动进行的。

撰写回答