代码之家  ›  专栏  ›  技术社区  ›  Falmarri

python内存泄漏,帧泄漏

  •  1
  • Falmarri  · 技术社区  · 14 年前

    我有这个代码来获取函数的文件名、行号和函数的调用方。不过,它好像在漏水,我不明白为什么。这是不是把我扔了,我的泄密肯定在别的地方?

            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()和frames进入gc.garbage列表的建议。甚至不接近正在创建的数量,尽管如show_most_common_types()中所示。我有一个关于范围的问题,在上面,没有 f 在for循环后超出范围?因为我刚试过:

    
    for f in range(20):
        l = 1
    
    print f
    

    它印了19张。那可能是我的 在for循环中泄漏?这是我的gc.garbage列表中的帧引用的引用图:

    alt text

    更新2 :

    alt text

    链接 here

    有办法清除检查模块吗?这些画面到底保存在哪里=\

    2 回复  |  直到 14 年前
        1
  •  1
  •   Ben Jackson    14 年前

    编辑我刚刚意识到这是错的 f f_back 两者指向相同的方向。我会留下它,以防它激励其他人:

    每个帧都有一个f}u 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 在你离开的路上。打破了循环引用。

        2
  •  1
  •   Falmarri    14 年前

    我想我找到了问题所在。多线程应用程序中的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)]
    

    它们都指向线程中的引导方法。我可能走错了方向,但其中一些框架的上下文离调用我发布的方法还很远。