从稳步增加的内存使用情况来看,我的一个python应用程序似乎泄漏了内存。我的假设是循环参考,尽管尽最大努力避免这种情况。为了找出问题,我正在研究如何手动检查无法访问的项目,这是一个纯粹用于调试的工具。了解Python的gc.garbage(用于跟踪内存泄漏)的问题
gc模块似乎能够进行必要的跟踪,并且我尝试了以下代码,旨在编译自上次调用后形成的不可缓存项目列表。第一次调用只是设置一个基本检查点,不会识别不可达的项目。
def unreachable():
# first time setup
import gc
gc.set_threshold(0) # only manual sweeps
gc.set_debug(gc.DEBUG_SAVEALL) # keep unreachable items as garbage
gc.enable() # start gc if not yet running (is this necessary?)
# operation
if gc.collect() == 0:
return 'no unreachable items'
s = 'unreachable items:\n ' \
+ '\n '.join('[%d] %s' % item for item in enumerate(gc.garbage))
_deep_purge_list(gc.garbage) # remove unreachable items
return s # return unreachable items as text
在这里,_deep_purge_list旨在手动中断周期并删除对象。以下实现处理一些常见的情况,但不是靠近水密的。我的第一个问题与此有关,请看下。
def _deep_purge_list(garbage):
for item in garbage:
if isinstance(item, dict):
item.clear()
if isinstance(item, list):
del item[:]
try:
item.__dict__.clear()
except:
pass
del garbage[:]
基于非常有限的测试,设置似乎正常工作。用下面的一个奇怪的现象发生
class A(object):
def __init__(self):
self.ref = self
print unreachable()
# no unreachable items
A()
print unreachable()
# unreachable items:
# [0] <__main__.A object at 0xb74579ac>
# [1] {'ref': <__main__.A object at 0xb74579ac>}
print unreachable()
# no unreachable items
但是:下列循环引用正确报告一次
print unreachable()
# no unreachable items
import numpy
print unreachable()
# unreachable items:
# [0] (<type '_ctypes.Array'>,)
# [1] {'__module__': 'numpy.ctypeslib', '__dict__': <attribute '__dict__' of 'c_long_Array_1' objects>, '__weakref__': <attribute '__weakref__' of 'c_long_Array_1' objects>, '_length_': 1, '_type_': <class 'ctypes.c_long'>, '__doc__': None}
# [2] <class 'numpy.ctypeslib.c_long_Array_1'>
# [3] <attribute '__dict__' of 'c_long_Array_1' objects>
# [4] <attribute '__weakref__' of 'c_long_Array_1' objects>
# [5] (<class 'numpy.ctypeslib.c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>)
print unreachable()
# unreachable items:
# [0] (<type '_ctypes.Array'>,)
# [1] {}
# [2] <class 'c_long_Array_1'>
# [3] (<class 'c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>)
重复调用的回头率那最后的结果。导入后第一次调用不可访问时,不会发生此问题。然而,在这一点上,我没有理由相信这个问题是具体的,我的猜测是它暴露了我的方法中的缺陷。
我的问题:
- 是否有更好的方法来去除gc.garbage项目?理想情况下, 有一种方法可以让gc移除它们,就像它会(应该)在没有DEBUG_SAVEALL的情况下完成 一样?
- 任何人都可以解释numpy导入的问题,和/或 建议如何解决它?
有感:
看来,下面的代码执行接近预期:
def unreachable():
import gc
gc.set_threshold(0)
gc.set_debug(gc.DEBUG_LEAK)
gc.enable()
print 'collecting {{{'
gc.collect()
print '}}} done'
然而,对于调试我更喜欢类型/ ID丰富的字符串表示,通过GC提供。此外,我想了解我以前的方法中的缺陷,并了解一下gc模块。
欣赏你的帮助,
Gertjan
更新06/05:
我遇到了一个情况:第一次执行未报告任何不可达的项目,除非当地人()被调用之前刚到它(丢弃返回值)。不理解这可能会如何影响gc的对象跟踪,这让我更加困惑。我不确定构建一个能够证明这个问题的小例子是多么容易,但是如果需求需要它,我可以给它一个机会。
我只是略过了这个,但你可能误解了'gc.DEBUG_SAVEALL':它意味着将被释放的对象追加到'gc.garbage'(而不是仅释放它们)。 – blueyed