2010-11-04 257 views
1

我有这段代码来获取函数的文件名,行号和函数的调用者。这似乎是漏帧虽然我不明白为什么。这只是把我扔掉,我的泄漏必须在其他地方?python内存泄漏,泄漏帧

 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所以这可能是我在for循环泄漏f?这是一个参考框架,这是在我的gc.garbage列表的参考图:

alt text

UPDATE2

它看起来像检查模块本身是抱着到框架的引用。这是来自实时帧的反向引用的对象图,而不是垃圾列表中的一个。

alt text

链接here,因为它太宽。

有没有办法清除检查模块?地狱是这些帧被保存= \

+0

你对退货rv做了什么? – 2010-11-04 01:35:00

+1

gc.set_debug(gc.DEBUG_LEAK)显示什么?您应该在其输出中看到泄漏的对象。 – dcolish 2010-11-04 03:14:21

+0

我甚至没有意识到我可以做到这一点,我必须在文档中对其进行扫描。当我回到电脑时,我会看到明天说的话 – Falmarri 2010-11-04 03:30:50

回答

1

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

alt text

在第三节点向下此处列出的function是inspect.getmodule()。我无法适应这一切,不得不做一些裁剪。

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

而且字典里面所有的帧

(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方法。我可能在这里错误的轨道上,但这些框架中的某些框架的背景远不及我所称的我发布的方法。

1

编辑我刚刚意识到这是错误的,f参考和f_back都指向相同的方式。我会离开它的情况下,它激发别人:

的每一帧都有一个f_back指针,所以当你设置f = inspect.stack()[1]然后inspect.stack()[0][0].f_locals(其中包含F)现在有一个参考...stack()[1]...stack()[1][0].f_back...stack()[0][0]。所以你创建了一个循环引用,它必须由GC解决,而不是简单地通过引用计数。 GC没有被调整来处理你创建对象的速度,所以你消耗的内存越来越多。

只需在出函数的路上设置f = None,就可以消除循环参考。这打破了循环引用。