Python的:内存泄漏调试(Python: Memory leak debugging)

2019-07-03 20:18发布

我一直在使用越来越多的内存在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秒。

我没有用孔雀鱼,因为它需要一个C扩展,我没有根,因此将是建立一个痛。

在objectI没有使用有一个__del__方法,并通过图书馆寻找,它看起来并不像Django的,也不是蟒蛇,MySQLdb的做无论是。 任何其他的想法?

Answer 1:

见http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/ 。 简短的回答:如果你正在运行的Django而不是在一个基于Web请求的格式,你需要手动运行db.reset_queries()当然有DEBUG = false,如其他人所说的)。 Django的自动执行reset_queries() web请求之后,但在您的格式,这永远不会发生。



Answer 2:

是DEBUG = false在settings.py?

如果不是Django会愉快地存储所有的SQL查询你做这些加起来。



Answer 3:

您是否尝试过gc.set_debug() ?

你需要问自己简单的问题:

  • 我使用的对象有__del__方法呢? 难道我绝对毫不含糊,需要它们?
  • 我可以参考的周期在我的代码? 我们不能摆脱的对象之前打破这些圈子吗?

见,主要的问题是包含对象的周期__del__方法:

import gc

class A(object):
    def __del__(self):
        print 'a deleted'
        if hasattr(self, 'b'):
            delattr(self, 'b')

class B(object):
    def __init__(self, a):
        self.a = a
    def __del__(self):
        print 'b deleted'
        del self.a


def createcycle():
    a = A()
    b = B(a)
    a.b = b
    return a, b

gc.set_debug(gc.DEBUG_LEAK)

a, b = createcycle()

# remove references
del a, b

# prints:
## gc: uncollectable <A 0x...>
## gc: uncollectable <B 0x...>
## gc: uncollectable <dict 0x...>
## gc: uncollectable <dict 0x...>
gc.collect()

# to solve this we break explicitely the cycles:
a, b = createcycle()
del a.b

del a, b

# objects are removed correctly:
## a deleted
## b deleted
gc.collect()

我真的鼓励你的标志物/概念在应用程序中循环,并专注于自己的一生:当你不需要他们了,难道我们有什么引用呢?

即使是无环__del__方法,我们可以有一个问题:

import gc

# class without destructor
class A(object): pass

def createcycle():
    # a -> b -> c 
    # ^         |
    # ^<--<--<--|
    a = A()
    b = A()
    a.next = b
    c = A()
    b.next = c
    c.next = a
    return a, b, b

gc.set_debug(gc.DEBUG_LEAK)

a, b, c = createcycle()
# since we have no __del__ methods, gc is able to collect the cycle:

del a, b, c
# no panic message, everything is collectable:
##gc: collectable <A 0x...>
##gc: collectable <A 0x...>
##gc: collectable <dict 0x...>
##gc: collectable <A 0x...>
##gc: collectable <dict 0x...>
##gc: collectable <dict 0x...>
gc.collect()

a, b, c = createcycle()

# but as long as we keep an exterior ref to the cycle...:
seen = dict()
seen[a] = True

# delete the cycle
del a, b, c
# nothing is collected
gc.collect()

如果你必须使用“看见”般的字典,还是历史,要小心,你只保留您需要的实际数据,并将其没有外部的引用。

我现在有点失望,由set_debug ,我希望它可以被配置为比标准错误在其他地方输出的数据,但希望应该很快就会改变 。



Answer 4:

见从斯内德尔德这个优秀的博客文章对他们在惠普的Tabblo如何追查下来真正的内存泄漏。 一个典型的和值得一读。



Answer 5:

我认为你应该使用不同的工具。 很显然,你得到的统计数据仅约GC对象(即可以参与周期的对象); 最值得注意的是,它缺乏的字符串。

我建议使用Pympler ; 这应该为您提供更详细的统计。



Answer 6:

你使用任何扩展? 它们是内存泄漏一个奇妙的地方,并且不会被Python工具进行跟踪。



Answer 7:

尝试孔雀鱼 。

基本上,你需要更多的信息,或者能够提取一些。 顾比甚至提供数据的图形表示。



文章来源: Python: Memory leak debugging