如何在环状数据结构中管理内存?

需求:
在python中,垃圾回收器通过引用计数来回收垃圾对象,但某些环状数据结构(树,图。。),存在对象间循环引用,比如树的父节点引用子节点,子节点也同时引用父节点。此时同时del掉引用父子节点,两个对象不能被立即回收。
如何解决此类的内存管理问题?

思路:
使用标准库weakref,它可以创建一种能访问对象但是不增加引用计数的对象

代码:

import weakref

# 下面构造两个类,他们互相引用
class Data(object):
    
    def __init__(self,value,owner):
        self.owner = weakref.ref(owner)  # 使用弱引用的方法,不增加计数
        self.value = value

    def __str__(self):
        return "%s's data,value is %s" % (self.owner(),self.value)

    def __del__(self):
        print('in Data.__del__')

class Node(object):
    
    def __init__(self,value):
        self.data = Data(value,self)

    def __del__(self):
        print('in Node.__del__')

node = Node(100)
del node        # 可以看到对象都被回收掉了
input('wait....')

======================================================

>>> class B():
...     def __del__(self):
...         print('in __del__')
... 
>>> b = B()
>>> b2 = weakref.ref(b)
>>> b3 = b2()
>>> b3 is b
True
>>> del b
>>> del b3
in __del__
>>> b2() is None
True
>>> b = B()
>>> b2 = weakref.ref(b)
>>> b2()
<__main__.B object at 0x7f74c52fa080>
>>> b()
Traceback (most recent call last):
  File "<ipython-input-60-3bf86fc5afda>", line 1, in <module>
    b()
TypeError: 'B' object is not callable

>>> b2
<weakref at 0x7f74c53d4138; to 'B' at 0x7f74c52fa080>
>>> B
<class '__main__.B'>
>>> b
<__main__.B object at 0x7f74c52fa080>
>>> 
=================================================
import weakref

class Node:
    def __init__(self,data):
        self.data = data
        self._left = None
        self.right = None

    def add_right(self,node):
        self.right = node
        node._left = weakref.ref(self) # 这里实现弱引用来解决内存释放的问题

    @property
    def left(self):
        return self._left() # 这里的括号是关键,通过括号的调用,返回引用对象的本身,而不是弱引用,从而达到左右对称

    def __str__(self):
        return 'Node:<%s>' % self.data

    def __del__(self):
        print('in __del__; delete %s' % self)

def create_linklist(n):
    head = Current = Node(1)
    for i in range(2,n+1):
        node  = Node(i)
        Current.add_right(node)
        Current = node
    return head

head = create_linklist(1000)
print(head.right,head.right.left)
input()
head = None

# 模拟函数运行
import time
for _ in range(1000):
    time.sleep(1)
    print('run...')
input('wait...')

posted @ 2020-07-27 23:37  Richardo-M-Lu  阅读(115)  评论(0编辑  收藏  举报