python终结器的概念:
内置数据类型的对象是不能设置终结器的,能定义终结器的只有用户创建的类
循环引用垃圾回收:
容器对象:可能保留了指向其他对象的引用的对象
这些对象都分配的用于循环引用垃圾回收的头结构体
/* GC information is stored BEFORE the object structure. */
typedef union _gc_head {
struct {
union _gc_head *gc_next;
union _gc_head *gc_prev;
Py_ssize_t gc_refs;
} gc;
long double dummy; /* force worst-case alignment */
} PyGC_Head;
前两个用于双向链表,最后一个是用于复制
dummy的作用如源码注释:即使结构体gc的大小不合理。它也会将整个结构体PyGC_Head的大小对齐为long double型
由下述代码负责分配所有容器对象的函数
PyObject *
_PyObject_GC_Malloc(size_t basicsize)
{
PyObject *op;
PyGC_Head *g;
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
return PyErr_NoMemory();
g = (PyGC_Head *)PyObject_MALLOC(
sizeof(PyGC_Head) + basicsize);/*此处可见,在分配对象时也额外分配了用于循环引用垃圾回收的头大小*/
if (g == NULL)
return PyErr_NoMemory();
g->gc.gc_refs = GC_UNTRACKED;/*GC_UNTRACKED存入用于循环引用垃圾回收的头内成员gc_refs,
当出现这个标志时,GC会认为这个容器对象没有连接到对象链*/
generations[0].count++; /* number of allocated GC objects */
if (generations[0].count > generations[0].threshold &&
enabled &&
generations[0].threshold &&
!collecting &&
!PyErr_Occurred()) {
collecting = 1;
collect_generations();
collecting = 0;
}
op = FROM_GC(g);/*这个会偏移用于循环垃圾引用的头的长度,返回正确的对象地址,
为了不区分容器对象和其他对象*/
return op;
}
#define GC_UNTRACKED _PyGC_REFS_UNTRACKED
gc_refs用负值做标志,这是为了节省空间
/* Get the object given the GC head */
#define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
追踪容器对象
这个宏放在各个容器对象新建立的时候,负责连接链表的操作
/* Tell the GC to track this object. NB: While the object is tracked the
* collector it must be safe to call the ob_traverse method. */
#define _PyObject_GC_TRACK(o) do { \
PyGC_Head *g = _Py_AS_GC(o); \ \*先从对象的开头地址开始,将头地址偏移相应的大小,
取出用于循环引用垃圾回收的头*\
if (g->gc.gc_refs != _PyGC_REFS_UNTRACKED) \
Py_FatalError("GC object already tracked"); \
g->gc.gc_refs = _PyGC_REFS_REACHABLE; \ \*修改gc_refs,表示可到达*\
g->gc.gc_next = _PyGC_generation0; \ \*拿出了连接所有容器对象的全局性容器对象链表,把对象链接到这个链表*\
g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \
g->gc.gc_prev->gc.gc_next = g; \
_PyGC_generation0->gc.gc_prev = g; \
} while (0);
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
同样的方式可以结束追踪对象;
/*** Global GC state ***/
struct gc_generation {
PyGC_Head head;
int threshold; /* collection threshold */
int count; /* count of allocations or collections of younger
generations */
};
这个结构体用于管理各代的容器对象,一旦count超过了threshold程序就会对这一代执行GC
0代 生成的容器对象的数量 - 删除的容器对象的数量
1代 0代经过GC的次数
2代 1代经过GC的次数
/* linked lists of container objects */
static struct gc_generation generations[NUM_GENERATIONS] = {
/* PyGC_Head, threshold, count */
{{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0},
{{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0},
{{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0},
};
PyGC_Head *_PyGC_generation0 = GEN_HEAD(0);
一开始的所有容器对象都连接着0代的对象