由於 CPython 使用 reference counting 管理記憶體, reference count 到 0 時會立即釋放記憶體, 遇到 memory leak 時, 至少可以用 del 稍微自救一番。
import sys a = [] print sys.getrefcount(a) # 2 b = a print sys.getrefcount(a) # 3 del b print sys.getrefcount(a) # 2
如上所示, 可在程式中用 sys.getrefcount() 檢查 referece count 是否符合預期, 盡量在不用以後立即呼叫 del, 當 reference count 變為 0 時, 會提前釋放記憶體。
注意 python 的 while、for 沒有形成新的 scope, 有可能因此誤判一些物件的生命週期:
for i in range(10): pass print i # 9, 並非 NameError
備註
附上 CPython 2.7.3 Include/object.h 內關於減 reference 相關的程式:
769 #define Py_DECREF(op) \ 770 do { \ 771 if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ 772 --((PyObject*)(op))->ob_refcnt != 0) \ 773 _Py_CHECK_REFCNT(op) \ 774 else \ 775 _Py_Dealloc((PyObject *)(op)); \ 776 } while (0)
可看出在 reference count 為 0 時, 確實會呼叫 deallocator。
今日休閒時間已用盡, 改天再來看看為什麼初始數值為 2。
傳給 getrefcount() 的時候變成他的 local variable 所以會 +1
回覆刪除就算有 circular reference 也可以 import gc; gc.collect() 收掉。
原來如此, 難怪最小值會是 2。
回覆刪除另外我是遇到 gc.collect() 無效時, 才被迫用這個方法, 可確實處理自己可掌握的部份。
比方說 a 擁有 b, 而 b 吃掉很多記憶體。a 傳給 third-party python container 後, 再從該 container 移除。但是 reference count 很神奇的在加入時多了 2+, 移除時卻只 -1, 所以 gc 的確不能收掉 a。我確定沒有人會再用到 a, 至少確定不會有程式再用到 a.b, 所以可以手動 del a.b, 提前釋放 a.b 的記憶體