在Python中,为了解决内存泄露问题,采用了对象引用计数,并基于引用计数实现自动垃圾回收。
由于Python 有了自动垃圾回收功能,就造成了不少初学者误认为不必再受内存泄漏的骚扰了。但如果仔细查看一下Python文档对 __del__() 函数的描述,就知道这种好日子里也是有阴云的。下面摘抄一点文档内容如下:
Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_traceback keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive). |
可见,有 __del__() 函数的对象间的循环引用是导致内存泄漏的主凶。但没有__del__()函数的对象间的循环引用是可以被垃圾回收器回收掉的。
如何知道一个对象是否内存泄露掉了呢?
可以通过Python的扩展模块gc来查看不能回收掉的对象的详细信息。
例
例1:没有出现内存泄露的
import gc import sys class CGcLeak(object): def __init__(self): self._text='#'*10 def __del__(self): pass def make_circle_ref(): _gcleak=CGcLeak() print("_gcleak ref count0:{}".format(sys.getrefcount(_gcleak))) del _gcleak try: print("_gcleak ref count:{}".format(sys.getrefcount(_gcleak))) except UnboundLocalError: print("_gcleak is invalid!") def test_gcleak(): gc.enable() print("begin leak test...") make_circle_ref() print " begin collect..." _unreachable = gc.collect() print("unreachable object num:{}".format(_unreachable)) print("garbage object num:{}".format(len(gc.garbage))) if __name__ == "__main__": test_gcleak()
结果
C:Python35python.exe C:/wcf/django/ftest/ftest.py begin leak test... _gcleak ref count0:2 _gcleak is invalid! unreachable object num:0 garbage object num:0 Process finished with exit code 0
例2:对自己的循环引用造成内存泄露
import gc import sys class CGcLeak(object): def __init__(self): self._text='#'*10 def __del__(self): pass def make_circle_ref(): _gcleak=CGcLeak() _gcleak._self = _gcleak print("_gcleak ref count0:{}".format(sys.getrefcount(_gcleak))) del _gcleak try: print("_gcleak ref count:{}".format(sys.getrefcount(_gcleak))) except UnboundLocalError: print("_gcleak is invalid!") def test_gcleak(): gc.enable() print("begin leak test...") make_circle_ref() print " begin collect..." _unreachable = gc.collect() print("unreachable object num:{}".format(_unreachable)) print("garbage object num:{}".format(len(gc.garbage))) if __name__ == "__main__": test_gcleak()
结果是:
C:Python35python.exe C:/wcf/django/ftest/ftest.py begin leak test... _gcleak ref count0:3 _gcleak is invalid! unreachable object num:2 garbage object num:0 Process finished with exit code 0
例3:多个对象间的循环引用造成内存泄露
import gc import sys class CGcLeakA(object): def __init__(self): self._text='#'*10 def __del__(self): pass class CGcLeakB(object): def __init__(self): self._text='$'*10 def __del__(self): pass def make_circle_ref(): _a=CGcLeakA() _b = CGcLeakB() _a.s=_b _b.s=_a print("ref count0:_a is {},_b is {}".format(sys.getrefcount(_a),sys.getrefcount(_a))) del _a del _b try: print("ref count:_a is {}".format(sys.getrefcount(_a))) except UnboundLocalError: print("_a is invalid!") def test_gcleak(): gc.enable() print("begin leak test...") make_circle_ref() print " begin collect..." _unreachable = gc.collect() print("unreachable object num:{}".format(_unreachable)) print("garbage object num:{}".format(len(gc.garbage))) if __name__ == "__main__": test_gcleak()
运行结果:
import gc import sys class CGcLeakA(object): def __init__(self): self._text='#'*10 def __del__(self): pass class CGcLeakB(object): def __init__(self): self._text='$'*10 def __del__(self): pass def make_circle_ref(): _a=CGcLeakA() _b = CGcLeakB() _a.s=_b _b.s=_a print("ref count0:_a is {},_b is {}".format(sys.getrefcount(_a),sys.getrefcount(_a))) del _a del _b try: print("ref count:_a is {}".format(sys.getrefcount(_a))) except UnboundLocalError: print("_a is invalid!") def test_gcleak(): gc.enable() print("begin leak test...") make_circle_ref() print " begin collect..." _unreachable = gc.collect() print("unreachable object num:{}".format(_unreachable)) print("garbage object num:{}".format(len(gc.garbage))) if __name__ == "__main__": test_gcleak()
转自:
http://www.cnblogs.com/kaituorensheng/p/4449457.html