Python:内存泄漏调试

Python:内存泄漏调试,python,django,debugging,memory-leaks,Python,Django,Debugging,Memory Leaks,我在django中运行了一个小的多线程脚本,随着时间的推移,它开始使用越来越多的内存。把它放一整天会吃掉大约6GB的内存,我开始交换 以下我认为这是最常见的类型(仅使用800M内存): 没有任何奇怪的地方。我现在应该做什么来帮助调试内存问题 更新:尝试一些人们推荐的东西。我一夜之间运行了这个程序,当我工作时,使用了50%*8G==4G的内存 (Pdb) from pympler import muppy (Pdb) muppy.print_summary()

我在django中运行了一个小的多线程脚本,随着时间的推移,它开始使用越来越多的内存。把它放一整天会吃掉大约6GB的内存,我开始交换

以下我认为这是最常见的类型(仅使用800M内存):

没有任何奇怪的地方。我现在应该做什么来帮助调试内存问题

更新:尝试一些人们推荐的东西。我一夜之间运行了这个程序,当我工作时,使用了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
来自Pypler导入muppy的
(Pdb)
(Pdb)多页打印摘要()
类型|#对象|总大小
========================================== | =========== | ============
unicode | 210997 | 97.64 MB
列表| 1547 | 88.29 MB
dict | 41630 | 13.21 MB
设置| 50 | 8.02 MB
str | 109360 | 7.11 MB
元组| 27898 | 2.29 MB
代码| 6907 | 1.16 MB
类型| 760 | 653.12 KB
weakref | 1014 | 87.14 KB
国际| 3552 | 83.25 KB
函数(uuu包装器_uuuu)| 702 | 82.27 KB
包装器|u描述符| 998 | 77.97 KB
单元格| 1357 | 74.21 KB
试试看


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

我认为您应该使用不同的工具。显然,您得到的统计数据只是关于GC对象(即可能参与循环的对象);最值得注意的是,它缺少字符串

我建议使用;这将为您提供更详细的统计信息。

您尝试过吗

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

  • 我是否将对象与
    \uu del\uu
    方法一起使用?我是否绝对、明确地需要它们
  • 我可以在代码中获得引用周期吗?我们不能在处理这些物体之前打破这些圆圈吗
请参阅,主要问题是包含
\uu del\uu
方法的对象循环:

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()
如果您必须使用“SEED”类词典或历史记录,请注意只保留所需的实际数据,而不保留对其的外部引用


我现在对设置调试有点失望,我希望它可以被配置为在其他地方输出数据,而不是输出到stderr,但希望如此。

您使用任何扩展吗?它们是内存泄漏的好地方,python工具不会跟踪它们。

settings.py中的DEBUG=False吗


如果没有的话,Django会很高兴地存储您所做的所有SQL查询,这些查询的总和。

请看他们是如何在HP的Tabblo中找到真正的内存泄漏的。经典之作,值得一读。

请参阅。简短回答:如果您正在运行django,但不是以基于web请求的格式运行,则需要手动运行
db.reset_querys()
(当然还有其他人提到的DEBUG=False)。Django会在web请求后自动执行
reset_querys()
,但以您的格式,这种情况永远不会发生。

top使用7%*8GB=560M显示我的应用程序。pympler.muppy.print_summary()显示大约55M。其余的在哪里?gc.collect()以可收集的形式返回所有内容,第二次调用返回0。这意味着我没有任何周期,对吗?@保罗:不,你仍然可以有周期。看看我给出的最后一个示例:这里,gc.collect()返回0,并且不打印任何内容。如果您有一个没有del方法的对象周期,gc将保持安静。没有扩展,但对于其他在这里跌跌撞撞的人来说是一个好地方。如果您使用Django ORM,您将使用扩展模块-DB-API数据库驱动程序。这是MySQLdb吗?当前版本在使用use_unicode=True建立连接时已知存在游标内存泄漏(Django>=1.0就是这种情况)。是的,你说得对!我用的都是这些。任何已知的解决方案?请尝试使用SVN的代码,漏洞已经修复,但更新尚未发布。“在Django中运行”?您的意思是说您正在使用DjangoWeb服务器进行额外的非web服务后台处理吗?您是否考虑过将这些非web服务的内容拆分成一个单独的进程?它是一个cron作业,导入Django settgings.py并使用许多Django ORM特性。因此,它不是由Web服务器产生的,但仍然使用了许多功能(可能是相关的)哇,我知道在那里写django这个词会有帮助。是的,我的脚本没有使用我的production settings.py。尴尬让我们看看它是否能解决内存问题。就是这样!当从大型数据库中选择时,DEBUG设置为True确实会占用大量内存。db.reset_querys()为我解决了一个问题,非常感谢。
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()
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()