弱引用确实是一个不太好理解的概念,本文就用图画给大家讲解一下什么是弱引用
第一部分:图画结合代码讲解弱引用概念 第二部分:weakref有什么用 第三部分:讲讲C语言中的弱引用众所周知,在Python与java中都有垃圾收集器(garbage collector)存在,当一个实例的引用计数记为0时,gc就会自动的回收内存。
弱引用一言以蔽之,就是它不会增加被引用对象的引用计数。即使弱引用存在,垃圾回收器也会当没看见一样,认为这个对象是可回收的。但是我们确实可以通过弱引用到达一个对象。
垃圾收集器会回收那些引用计数被记为0的对象,但是对非常复杂的数据结构,可能会存在互相引用而造成死锁的情况,如下图所示: 假设存在对象A,对象B,对象A,B互相强引用。
在这种情况下,A的引用计数为1,B的引用计数为1,垃圾回收器不会自动的回收它,我们只能去手动的运行垃圾回收器。
代码展示如下:
class Node: def __init__(self): self.parent=None self.child=None def add_child(self,child): self.child=child child.parent=self def __del__(self): print('deleted')上面的代码定义了一个类。这个类的实例对象被删除时,会打印出“deleted”。
我们在解释器试一下...
可以看到del a时正确的打印出了deleted,说明垃圾回收器正确的回收了实例。
上面的演示,可以看到,当两个节点互相引用时,del a后,并没有显示deleted,说明实例没有被正确的回收。只有当我们手动的运行垃圾回收器时,实例才被正确的回收。
那么如下图这样,当A强引用B,而B对A是弱引用的时候,垃圾回收器会正确的回收吗?
代码编写如下:
import weakref class Node: def __init__(self): self.parent=None self.child=None def add_child(self,child): self.child=child child.parent=weakref.ref(self) def __del__(self): print('deleted')可以看到当两个节点实例变成不可达对象后,回收器正确的回收了内存。在gc眼中,此时A,B两个实例的引用就像下图这样。
A的引用计数已经为0,gc回收了它,B的引用计数也变为了0,gc再回收它。如此,内存被正确回收。
弱引用的一个用处就是实现缓存。
弱引用简单的来说,当它引用的对象存在时,则对象可用,当对象不存在时,就返回None,说明对象不存在。程序不会因为对象不在就报错。
这正和缓存的性质一样,缓存就是一个有则用,无则重新获取的技术。
C语言中同样有弱引用,它与程序的链接密切相关。
在《程序员的自我修养-装载,链接与库》一书中,3.5.5节讲到了弱引用。这里将原文给大家看一下:
在GCC中指定一个符号为弱引用,可以使用_attribute__((weakref))拓展关键字。我想上文对于链接器如何看待强弱引用讲的很清楚了。
谢谢你读完本文,有什么错误可以在评论区指正!!
欢迎点赞给作者一点鼓励!