Python的垃圾回收采用的是自动引用计数方式,但是引用计数会存在循环引用的问题,为了解决循环引用的问题,Python提供了一种“标记-清除”的垃圾回收机制。
引用计数
Python中的每个对象都有一个引用计数器,用于记录对象被引用的次数。当对象的引用计数为0时,它便可被垃圾回收。
举个例子:
a = 'foo'
b = a
del a
以上代码中,当a
的引用计数变为0时,垃圾回收机制就会将其回收。
但是,当存在循环引用时,引用计数会出现问题:
class Node(object):
def __init__(self, value=None):
self.value = value
self._next = None
@property
def next(self):
return self._next
@next.setter
def next(self, node):
self._next = node
a = Node(1)
b = Node(2)
a.next = b
b.next = a
该代码中,a
和b
对象彼此引用,导致它们的引用计数为不为0,进而导致无法被垃圾回收。
标记-清除
“标记-清除”机制是Python解决循环引用问题的一种方式。
首先,Python在内存中给每个对象分配一个标记。当垃圾回收机制触发时,Python会从根对象(如全局对象、局部对象)开始遍历,标记所有可以访问到的对象。标记完成后,Python将扫描所有对象,将未被标记的对象删除,从而清除无用对象。
举个例子:
class Node(object):
def __init__(self, value=None):
self.value = value
self._next = None
@property
def next(self):
return self._next
@next.setter
def next(self, node):
self._next = node
a = Node(1)
b = Node(2)
a.next = b
b.next = a
# 这里手动清除a和b对象
a.next = None
b.next = None
import gc
gc.collect() # 手动触发垃圾回收
以上代码中,手动清除了a
和b
对象之间的引用关系,使它们的引用计数变为0。接着使用gc.collect()
手动触发垃圾回收。gc的执行结果:
gc: collectable <Node 0x104957320>
gc: collectable <Node 0x10495f908>
gc: freeing <Node 0x104957320>
gc: freeing <Node 0x10495f908>
可以看到,垃圾回收机制清除了无用的循环引用对象。
总结:Python垃圾回收主要采用自动引用计数和“标记-清除”机制。其中自动引用计数机制用于回收引用计数为0的对象,而“标记-清除”机制则用于回收循环引用对象。