Python源码解析: PyObject 引用计数 refchain
版本,Python3.7.2
引用计数器的管理
Python通过引用计数来管理对象的生命周期,同时,其多态性也与引用计数有关。
Python对所有的对象,都是通过其父类PyObject进行统一管理。
_Py_NewReference(PyObject *op)这个函数相当简单,就是初始化计数op->refcnt=1,同时,该函数把新创建的这个PyObject* op添加到refchain,在下面的代码中,_Py_AddToAllObjects的关键几行特意给出了数字标注,插入op的过程如下图所示,其中(1)(2)(3)(4)分别对应图中建立的箭头1,2,3,4所示的关系
void _Py_AddToAllObjects(PyObject *op, int force){
....
if (force || op->_ob_prev == NULL) {
op->_ob_next = refchain._ob_next; (1)
op->_ob_prev = &refchain; (2)
refchain._ob_next->_ob_prev = op; (3)
refchain._ob_next = op; (4)
}
}
_Py_NewReference(PyObject *op)
{
_Py_INC_REFTOTAL; // _Py_RefTotal++
op->ob_refcnt = 1;
_Py_AddToAllObjects(op, 1);
_Py_INC_TPALLOCS(op);
}
函数_Py_ForgetReference(PyObject *op)就是上述创建过程的逆过程,也就是把PyObject* op从refchain链中删除掉, 典型的情况下,_Py_Dealloc(PyObject *op)会调用该_Py_ForgetReference函数并负责调用相关的析构函数来清理内存。这里也是一个典型的由C构造出来的多态性,析构函数dealloc由不同的对象根据自身的类型决定,也就是Py_TYPE(op)->tp_dealloc,比如List和float类型的对象,析构函数就不一样,源码如下所示
void _Py_ForgetReference(PyObject *op)
{
....
// main part of the removal
op->_ob_next->_ob_prev = op->_ob_prev;
op->_ob_prev->_ob_next = op->_ob_next;
op->_ob_next = op->_ob_prev = NULL;
}
void _Py_Dealloc(PyObject *op)
{
destructor dealloc = Py_TYPE(op)->tp_dealloc;
_Py_ForgetReference(op);
(*dealloc)(op);
}