python内存泄漏,漏洞

时间:2010-11-04 01:26:31

标签: python memory-leaks

我有这个代码来获取我的函数的文件名,行号和函数的调用者。它似乎是泄漏框架,我不明白为什么。这只是让我失望,我的泄漏必须在其他地方吗?

        rv = "(unknown file)", 0, "(unknown function)"

            for f in inspect.stack()[1:]:
                if __file__ in f:
                    continue
                else:
                    rv = f[1:4]
                    break

        return rv

我没有在任何地方保存对框架的引用。但它肯定是漏洞的框架:

> objcallgraph.show_most_common_types()
>tuple                      24798
>frame                      9601
>...

更新: 我的镜架肯定是泄露了。我做了关于gc.set_debug()的建议,帧很慢进入gc.garbage列表。尽管如show_most_common_types()中所示,但创建的数量仍然很少。我有关于范围的问题,但在上面,在for循环之后f是否超出了范围?因为我刚试过这个:


for f in range(20):
    l = 1

print f

并且它打印了19.所以它可能是我的f在for循环泄漏?这是我的gc.garbage列表中的框架引用的参考图:

alt text

UPDATE2

看起来检查模块本身正在保持对框架的引用。这是来自实时帧的反向引用的对象图,而不是垃圾列表中的反向引用。

alt text

链接here,因为它太宽了。

有没有办法清理检查模块?这些帧在哪里被保存= \

2 个答案:

答案 0 :(得分:1)

编辑我刚刚意识到这是错误的,f引用和f_back都指向同一个方向。我会留下它,以防它激励别人:

每个框架都有一个f_back指针,因此当您设置f = inspect.stack()[1]时,inspect.stack()[0][0].f_locals(包含f)现在引用...stack()[1]...stack()[1][0].f_back指向{{ 1}}。因此,您创建了一个循环引用,必须由GC解决,而不是仅通过引用计数。 GC未经过调整以处理您的对象创建速率,因此您消耗的内存越来越多。

您可以通过在离开函数的路上设置...stack()[0][0]来消除循环引用。这打破了循环引用。

答案 1 :(得分:1)

我觉得我发现了问题。这似乎是一个问题,检查模块和多线程应用程序中的底层C代码。具有上述代码的模块正在从不同的线程导入。第二张图指出了这个问题。

alt text

第三个节点中列出的function是inspect.getmodule()。我不能把它全部放在那里,不得不做一些裁剪。

(Pdb) objgraph.at(3510928)
<cell at 0x359290: dict object at 0x3849c0>

在dict里面是所有的框架

(Pdb) objgraph.at(0x3849c0)

     {(<frame object at 0x97a288>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
     (<frame object at 0x896288>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
     (<frame object at 0xa621b0>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
     (<frame object at 0x11266e8>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
    ...}

如果你得到所有那些帧的外框

(Pdb) inspect.getouterframes(objgraph.at(0x97a288))
[(<frame object at 0x97a288>, '/lib/python26.zip/logging/__init__.py', 1028, 'debug', ['            self._log(DEBUG, msg, args, **kwargs)\n'], 0),
 (<frame object at 0x794040>, '/lib/python26.zip/logging/__init__.py', 1505, 'debug', ['    root.debug(*((msg,)+args), **kwargs)\n'], 0),
 (<frame object at 0x794e58>, '/mmc/src/core/controller/main.py', 1046, '__startCharge', ['            self.chargeLock.release()\n'], 0),
 (<frame object at 0x5c4260>, '/mmc/src/core/controller/main.py', 1420, 'watchScheduleStartChargeCondition', ['                        ret = self.__startCharge(0, eventCode=eventCode)\n'], 0),
 (<frame object at 0x5c0dd0>, '/home/ephibian/Python2/_install/lib/python2.6/threading.py', 484, 'run', None, None),
 (<frame object at 0x5c3b48>, '/home/ephibian/Python2/_install/lib/python2.6/threading.py', 532, '__bootstrap_inner', None, None),
 (<frame object at 0x218170>, '/home/ephibian/Python2/_install/lib/python2.6/threading.py', 504, '__bootstrap', None, None)]

它们都指向线程中的__bootstrap方法。我可能在这里错误的轨道,但其中一些框架的上下文远不及我称之为我发布的方法。