一文看懂弱引用!Python中的weakref有什么用?

    技术2022-07-11  95

    弱引用确实是一个不太好理解的概念,本文就用图画给大家讲解一下什么是弱引用

    第一部分:图画结合代码讲解弱引用概念 第二部分: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再回收它。如此,内存被正确回收。

    第二部分:weakref有什么用

    弱引用的一个用处就是实现缓存。

    弱引用简单的来说,当它引用的对象存在时,则对象可用,当对象不存在时,就返回None,说明对象不存在。程序不会因为对象不在就报错。

    这正和缓存的性质一样,缓存就是一个有则用,无则重新获取的技术。

    第三部分:C语言中的弱引用

    C语言中同样有弱引用,它与程序的链接密切相关。

    在《程序员的自我修养-装载,链接与库》一书中,3.5.5节讲到了弱引用。这里将原文给大家看一下:

    在GCC中指定一个符号为弱引用,可以使用_attribute__((weakref))拓展关键字。我想上文对于链接器如何看待强弱引用讲的很清楚了。


    谢谢你读完本文,有什么错误可以在评论区指正!!

    欢迎点赞给作者一点鼓励!

    Processed: 0.011, SQL: 9