17.2_引用计数方式的内存管理

17.2 引用计数方式的内存管理

Python的基础内存管理方式是引用计数。引用计数的机制很简单(因此效率很高)。每个对象在被创建时的引用计数为0,当它被另一个对象引用时,引用计数加1,当引用停止时,引用计数减1。最终,当引用计数变为0时,Python解释器会回收该对象。在引用计数中,当对象不再被需要时,会立即从内存中删除。这就是引用计数方式的内存管理。

以下是导致引用计数增加的情况。

  • 使用赋值运算符时
    \bullet 向函数传递参数时
    向容器类型对象(列表、元组和类等)添加对象时

上述情况会导致引用计数增加。示例代码如下所示

class obj: pass   
def f(x): print(x)   
a = obj() #引用计数为1   
f(a) #进入函数后引用计数为2   
#离开函数后引用计数为1   
a = None #引用计数为0

在上面的代码中,a是由obj()创建的对象①的引用。此时该对象的引用计数为1。之后调用了函数f(a),其中a作为参数传递给函数,所以在函数作用域内,引用计数加1(合计为2)。在对象离开函数作用域时,引用计数减1。最后,当a = None时,对象的引用计数为0(它不再被任何对象引用)。此时,对象会立即从内存中释放。

由此可见,引用计数的机制很简单。不过这个简单的机制解决了许多内存使用相关的问题。我们再来看看下面的示例代码。

a = obj()
b = obj()
c = obj()
a.b = b
b.c = c
a = b = c = None

上面的代码创建了a、b、c这3个对象。a引用了b,b引用了c。此时,对象之间的关系如图17-1左图所示。


图17-1 对象关系图(虚线表示引用,数字表示引用计数)

如图17-1右图所示,当 a=b=c=Nonea = b = c = \text{None} 时,对象之间的关系发生变化。此时a的引用计数变为0(b和c的引用计数为1)。因此,a立即被删除。删除a导致b的引用计数从1变成0,因此b也被删除。同理,删除b导致c的引用计数从1变成0,c也被删除。这是一种类似于多米诺骨牌的机制,可以一次性删除用户不再使用的对象。

这就是Python的内存管理方法——引用计数。它解决了很多内存管理的问题,但是,有一个问题是不能用引用计数来解决的,这个问题就是循环引用。