需求:
在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...')