2010-11-04 256 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,就可以消除循環參考。這打破了循環引用。