Python垃圾回收
Python垃圾回收的工作原理是:为每个内存对象维护一个引用计数,当对象的引用计数为零时解释器会自动释放内存。
在Python中,有2中方式可以触发垃圾回收:一种方式是用户显示调用gc.collect(),另一种方式是每次Python为新对象分配内存时,检查threshold阀值,当对象数量超过threshold设置的阀值就开始进行垃圾回收。但是Python垃圾回收频频触发会影响程序执行的性能。
优化前:频繁做无用垃圾回收
[root@xiaoxiong gc]# cat 2.py
data = range(1,4000000)
wdict = dict(zip(data,data))
[root@xiaoxiong gc]# time python 2.py
real 0m17.551s
user 0m17.123s
sys 0m0.420s
[root@xiaoxiong gc]#
优化后的垃圾回收程序
[root@xiaoxiong gc]# cat 1.py
import gc
gc.disable()
data = range(1,5000000)
wdict = dict(zip(data,data))
gc.enable()
[root@xiaoxiong gc]#
[root@xiaoxiong gc]#
[root@xiaoxiong gc]# time python 1.py
real 0m2.596s
user 0m2.068s
sys 0m0.513s
[root@xiaoxiong gc]#
优化前的程序无法释放部分内存,而垃圾回收程序却在做无用功,程序的执行性能将大打折扣。调优后在程序片段运行的这段时间内禁止进行垃圾回收,程序性能大为提高。
Python内存泄露
Python虽然能自动垃圾回收,但是如果使用不当,也会造成内存泄露,造成这种现象的原因一般都是由于某些对象引用了自身,造成了类似的一个引用循环。
下面的程序提供了更多的信息来帮助定位泄露发生地点的办法。
[root@xiaoxiong cb8]#
[root@xiaoxiong cb8]# cat 1.py
import gc, time
def dump_garbage():
""" show us what the garbage is about """
# Force collection
print "\nGARBAGE:"
gc.collect()
print "\nGARBAGE OBJECTS:"
for x in gc.garbage:
print 'hello'
s = str(x)
#if len(s) > 80: s = s[:77]+'...'
print type(x),"\n ", s
class Obj:
def __init__(self,name='A'):
self.name = name
print '%s inited' % self.name
def __del__(self):
print '%s deleted' % self.name
def hello():
dump_garbage()
if __name__=="__main__":
gc.enable()
gc.set_debug(gc.DEBUG_LEAK)
# Simulate a leak (a list referring to itself) and show it
a = Obj('A')
b = Obj('B')
c = Obj('c')
c.attrObj = b
b.attrObj = c
del a
del b
del c
[root@xiaoxiong cb8]# python 1.py
A inited
B inited
c inited
A deleted
GARBAGE:
gc: uncollectable <Obj instance at 0x7f59410c9ea8>
gc: uncollectable <Obj instance at 0x7f59410c9dd0>
gc: uncollectable <dict 0x129f310>
gc: uncollectable <dict 0x12af7f0>
GARBAGE OBJECTS:
hello
<type 'instance'>
<__main__.Obj instance at 0x7f59410c9ea8>
hello
<type 'instance'>
<__main__.Obj instance at 0x7f59410c9dd0>
hello
<type 'dict'>
{'name': 'B', 'attrObj': <__main__.Obj instance at 0x7f59410c9dd0>}
hello
<type 'dict'>
{'name': 'c', 'attrObj': <__main__.Obj instance at 0x7f59410c9ea8>}
[root@xiaoxiong cb8]#
该程序第一步调用gc.set_debug,通知gc模块将泄露的对象放入gc.garbage列表中,而不是将它们回收利用。然后dump_garbage函数调用gc.collect来强制回收进程的运行,即使当前内存还很充裕,这样它就可以检查gc.garbage中的每一项并打印出类型和内容。