- 问题出现环境:python 2.7.1(X)及以下, Windows(或CentOS)
这个问题产生在lib/urllib2.py的line 1174 (python 2.7.1),导致形成了cycle,即使调用gc.collect()也不能释放到HttpResponse等相关联对象(gc.garbage可以查看)
1 r.recv = r.read 2 3 fp = socket._fileobject(r, close=True) 4 5 resp = addinfourl(fp, r.msg, req.get_full_url()) 6 7 resp.code = r.status 8 9 resp.msg = r.reason10 11 return resp
在python官方网站上很早发现了此BUG(见以下两个issues),但就是没有正式解决此问题。不过以下两个threads可以得到workarounds。
- 引申一下,如果python代码写成这样(自己写代码犯的一个错误),会导致以上相同cycle问题,从而导致内存泄漏。
1 class T(object):2 def __init__(self):3 self.test = self.test04 5 def test0(self, d={}):6 d['a'] = 1
在python shell运行如下:
1 Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32 2 Type "help", "copyright", "credits" or "license" for more information. 3 >>> import gc 4 >>> gc.set_debug(gc.DEBUG_LEAK) 5 >>> class T(object): 6 ... def __init__(self): 7 ... self.test = self.test0 8 ... 9 ... def test0(self, d={}):10 ... d['a'] = 111 ...12 >>> t=T()13 >>> del t14 >>> gc.collect()15 gc: collectable16 gc: collectable 17 gc: collectable 18 319 >>> for _item in gc.garbage:20 ... print _item21 ...22 <__main__.T object at 0x0260D870>23 >24 { 'test': >}
导致不能释放内存即是以上红色字体部分,可以通过调用GC自带两方法查看为什么会形成cycle。
1 >>> t2=T() 2 >>> gc.get_referrers(t2) 3 [>, { '__builtins__': , 't2': <__main__.T object at 0x0260D890>, '__package__': None, 'gc' 4 : , 'T': , '__name__': '__main__', '__doc__': None, '_item': { 'test': >}}] 5 >>> for _item in gc.get_referrers(t2): 6 ... print _item 7 ... 8 > 9 { '__builtins__': , 't2': <__main__.T object at 0x0260D890>, '__package__': None, 'gc': , 'T': , '__name10 __': '__main__', '__doc__': None, '_item': {...}}11 >>> for _item in gc.get_referents(t2):12 ... print _item13 ...14 {'test': >}15
gc.get_referrers:Return the list of objects that directly refer to any of objs. 返回引用t2的对象,包括>对象
gc.get_referents:Return a list of objects directly referred to by any of the arguments.
返回被t2引用的对象,包括>对象
- 以下情况不产生cycle:
1 class T2(object): 2 def __init__(self): 3 pass 4 5 def test(self): 6 return self.test0() 7 8 def test0(self, d={}): 9 d['a'] = 110 class T3(object):11 def __init__(self):12 self.test = self.test013 14 @classmethod 15 def test0(cls, d={}):16 d['a'] = 117 kkk = test0