枫叶居

桃李春风一杯酒,江湖夜雨十年灯

0%

Python内存回收机制

Python2.7内存回收机制(一)

写在前面

Python的内存回收采用引用计数机制。引用计数是一种简单而广泛使用的资源回收机制,例如Linux平台的文件描述符Windows平台下的内核对象等均采用引用计数的方式进行管理。本文将结合Python2.7官方手册阐明Python2.7引用计数机制(如无特殊说明,本文所提及的Python均为CPython)。

Python语言在设计之初就是一门面向对象的语言,即一切皆为对象,在Python官方介绍通用对象结构Common Object Structures一文中,有这样一段话:

All Python objects ultimately share a small number of fields at the beginning of the object’s representation in memory. These are represented by thePyObject and PyVarObject types, which are defined, in turn, by the expansions of some macros also used, whether directly or indirectly, in the definition of all other Python objects.

简单来说,Python中所有对象的开始位置,都有一组成员变量,以C语言的两个自定义类型——PyObjectPyVarObject来表示(有兴趣的,可以通读Common Object Structures一文,或者参考《Python源代码剖析》一书,这里不做具体阐述),PyObjectPyVarObject的开始位置都有一组相同的成员变量(分别由宏PyObject_HEADPyObject_HEAD扩展):

1
2
Py_ssize_t ob_refcnt;  // 对象引用计数
PyTypeObject *ob_type; // 指向对象类型结构体的指针(与本文无关不做具体阐述)

由此可见,在CPython实现中,每个Python对象均有一个名为ob_refcnt的成员变量用于标识该对象的引用计数。而众所周知,在Python的实现中,变量只是保存了一个对象的引用(即指针),而非对象本身,所以每当一个Python对象被一个不同变量所引用时,对象的引用计数就会+1,相反当变量不再引用该对象时,该对象的引用计数就会-1,当对象的引用计数变为0时,该对象就会在未来的某个时间被Python的垃圾回收器所回收。

通过Pythonsys模块的getrefcount方法可以获取Python对象的当前引用计数:

1
2
3
4
5
6
7
8
9
10
11
# -*- coding: utf-8 -*-

import sys


class A(object):
pass

a = A()
b = c = a
print(sys.getrefcount(a))
 示例运行结果为4,比实际引用数量(a, b, c)多1,那么为什么会这样呢,`sys.getrefcount`的文档作出了说明:

 >Return the reference count of the *object*. The count returned is generally one higher than you might expect, because it includes the (temporary) reference as an argument to [`getrefcount()`](https://docs.python.org/2.7/library/sys.html#sys.getrefcount).

 把对象当做参数调用`sys.getrefcount`方法会增加对象的一个临时引用计数。
坚持原创技术分享,您的支持将鼓励我继续创作!