import gc, ctypes
def get_object(obj_id):
return ctypes.cast(obj_id, ctypes.py_object).value
class Node:
def __init__(self, val):
self.val = val
self.prev = None
self.next = None
def __repr__(self):
return "Node(%s)" % self.val
first, second = Node(1), Node(2)
id_first, id_second = id(first), id(second)
first.next, second.prev = second, first
print("ref count of first node: %s" % len(gc.get_referrers(first)))
print("ref count of second node: %s" % len(gc.get_referrers(second)))
print("delete first node")
del first
print("ref count of first node: %s" % len(gc.get_referrers(get_object(id_first))))
print("delete second node")
del second
print("ref count of first node: %s" % len(gc.get_referrers(get_object(id_first))))
print("ref count of second node: %s" % len(gc.get_referrers(get_object(id_second))))
输出结果
ref count of first node: 2
ref count of second node: 2
delete first node
ref count of first node: 1
delete second node
ref count of first node: 1
ref count of second node: 1
print("execute garbage collecting")
gc.collect()
print("ref count of first node: %s" % len(gc.get_referrers(get_object(id_first))))
print("ref count of second node: %s" % len(gc.get_referrers(get_object(id_second))))
执行结果:
execute garbage collecting
ref count of first node: 0
ref count of second node: 0
解决方法二
import gc, ctypes, weakref
def get_object(obj_id):
return ctypes.cast(obj_id, ctypes.py_object).value
class Node:
def __init__(self, val):
self.val = val
self.prev = None
self.next = None
def __repr__(self):
return "Node(%s)" % self.val
first, second = Node(1), Node(2)
id_first, id_second = id(first), id(second)
first.next, second.prev = weakref.ref(second), weakref.ref(first)
print("ref count of first node: %s" % len(gc.get_referrers(first)))
print("ref count of second node: %s" % len(gc.get_referrers(second)))
print("delete first node")
del first
print("ref count of first node: %s" % len(gc.get_referrers(get_object(id_first))))
print("delete second node")
del second
print("ref count of first node: %s" % len(gc.get_referrers(get_object(id_first))))
print("ref count of second node: %s" % len(gc.get_referrers(get_object(id_second))))
执行结果:
ref count of first node: 1
ref count of second node: 1
delete first node
ref count of first node: 0
delete second node
ref count of first node: 0
ref count of second node: 0
Python垃圾回收使用的是引用计数的方式,当一个对象不再有任何引用和它关联时,它的引用计数变为0,将会触发Python的垃圾回收系统对其进行回收。
但是如果遇到两个对象相互引用的情况,例如双向链表中的相邻两个节点,Python的垃圾回收系统就不能很好地工作了。
输出结果
删除first后,first的引用计数为1,因为此时second.prev指向了first,first对应的对象无法被回收 删除second后,second的引用计数为1,因为此时first对应的对象的next属性指向second
随着程序的执行,越来越多的循环引用占用的内存无法释放,将可能导致内存泄漏~
解决方法一
Python有另外的垃圾回收器来专门针对循环引用的,但是你永远不知道它什么时候会触发。 你还可以手动的触发它:
执行结果:
解决方法二
执行结果: