每一门包含垃圾回收器的语言中,不可避免的存在引用的两个问题:强引用与弱引用。
当一个对象赋值时,默认就是强引用类型,即必须等待该对象所有的引用计数为,对象内存才会被回收。当出现循环引用或缓存对象时,如不进行显示清除,则可能会导致系统内存泄露(根据不同的垃圾回收算法决定)。弱引用则可以解决这些问题,当系统出现内存紧张时,不用显示析构对象,垃圾回收器会自动回收弱引用对象,弱引用被引用后,引用计数也不会增加;弱引用实际上在目标对象中增加了一层代理。
import weakref,sys
import os,time
class A:
def __init__(self,obj):
self.obj = obj
print("class A")
def __call__(self,obj=None):
print("Call A")
def __del__(self):
print("del A")
def func(self):
print("A func.")
class B:
def __init__(self):
self.obj = None
print("class B")
def __call__(self,obj=None):
print("call B")
def __del__(self):
print("del B")
def func(self):
print("B func")
if__name__ == "__main__":
o =B()
b = weakref.ref(o)
a = A(b)
print("ref counta:%s,b:%s,b():%s"%(sys.getrefcount(a),sys.getrefcount(b),sys.getrefcount(b())))
b().obj = a
print("ref counta:%s,b:%s,b():%s"%(sys.getrefcount(a),sys.getrefcount(b),sys.getrefcount(b())))
del a
print("sleep now.")
time.sleep(3)
上面的程序中,对象b为弱引用,A,B嵌套引用,循环引用现象并未导致内存泄露输出结果如下:
class B
class A
ref count a:2,b:3,b():2
ref count a:3,b:3,b():2
sleep now.
del B
del A
getrefcount函数实参引用了一个对象故比原引用多了一个引用,对象a、对象b创建初始计数为1,对象b被对象a引用、初始创建引用计数为2;当b的代理对象引用对象a后,a的引用计数则增加为2。
强引用之间的循环引用则会导致内存泄露。如下面的实例:
b = B()
a = A(b)
b.obj = a
del a
del b
输出结果如下:
class B
class A
对象a、b均未释放,产生了内存泄露。
领取专属 10元无门槛券
私享最新 技术干货