在Python内部记录着所有使用中的对象各有多少引用。
一个内部跟踪变量,称为一个引用计数器。
当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,
也就是说,这个对象的引用计数变为0 时,它被垃圾回收。但是回收
不是"立即"的,由解释器在适当的时机,将垃圾对象占用的内存空间回收。
#引用计数:
#coding=utf-8 import sys print (sys.getrefcount(500111)) a = 5001111 # 创建对象<5001111> print (sys.getrefcount(a)) b = a # 增加引用,<5001111>的计数 print (sys.getrefcount(5001111 )) c = [b] # 增加引用. <5001111>的计数 print (sys.getrefcount(5001111)) del a # 减少引用<5001111>的计数 print (sys.getrefcount(5001111)) b = 100 # 减少引用<5001111>的计数 print (sys.getrefcount(5001111 )) c[0] = -1 # 减少引用<5001111>的计数 print (sys.getrefcount(5001111))
E:>py -3 a.py
3
4
5
6
5
4
3
#垃圾回收
垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。
循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情
况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计
数器和一个循环垃圾收集器。作为引用计数的补充,垃圾收集器也会留心被
分配的总量很大(及未通过引用计数销毁的那些)的对象。在这种情况下,
解释器会暂停下来,试图清理所有未引用的循环。
析构函数 __del__ ,__del__在对象销毁的时候被调用,当对象不再被使用时,
__del__方法运行:
import time class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print (class_name, "销毁") pt1 = Point() pt2 = pt1 pt3 = pt1 print (id(pt1), id(pt2), id(pt3)) # 打印对象的id del pt1 del pt2 time.sleep(5) del pt3
E:>py -3 a.py
65749120 65749120 65749120
Point 销毁
#循环引用的对象被回收
class LeakTest: def __init__(self): self.a = None self.b = None print ("object = %d born here." % id(self)) A = LeakTest() B = LeakTest() A.a = B B.b = A import sys print (sys.getrefcount(A)) print (sys.getrefcount(B)) del A try: print (sys.getrefcount(A)) except Exception as e: print (e) del B try: print (sys.getrefcount(B)) except Exception as e: print (e)
E:>py -3 a.py
object = 65654400 born here.
object = 65654568 born here.
3
3
name 'A' is not defined
name 'B' is not defined