Python源码剖析[11] —— PyListObject对象(3)
来源:互联网 发布:明治奶粉淘宝 编辑:程序博客网 时间:2024/06/06 00:31
[绝对原创 转载请注明出处]
Python源码剖析
——PyListObject对象(3)
本文作者: Robert Chen (search.pythoner@gmail.com )
3. PyListObject对象缓冲池
还记得吗,刚才我们按下了一个有趣的话题。没错,就是那个缓冲池,free_list。现在,是揭开它的神秘面纱的时候呢。我们想知道的问题是:free_list中所缓冲的PyListObject对象是从哪里获得的,是在何时创建的。答案就在一个PyListObject被销毁的过程中:
[listobject.c]
static void list_dealloc(PyListObject *op)
{
int i;
PyObject_GC_UnTrack(op);
Py_TRASHCAN_SAFE_BEGIN(op)
if (op->ob_item != NULL) {
/* Do it backwards, for Christian Tismer.
There's a simple test case where somehow this reduces
thrashing when a *very* large list is created and
immediately deleted. */
i = op->ob_size;
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]);
}
PyMem_FREE(op->ob_item);
}
if (num_free_lists < MAXFREELISTS && PyList_CheckExact(op))
free_lists[num_free_lists++] = op;
else
op->ob_type->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op)
}
在销毁一个PyListObject的时候,当然要做的一件事是为list中的每一个元素改变其引用计数。然后,我们就来到了最有趣的部分。Python会检查我们开始提到的那个缓冲池,free_lists,查看其中缓存的PyListObject的数量是否已经满了,如果没有,就将该待删除的PyListObject放到缓冲池中,以备后用。现在一切真相大白了,那个在Python启动是空荡荡的缓冲池原来都是被本应该死去的PyListObject对象给填充了 ,在以后创建新的PyListObject的时候,Python会首先唤醒这些已经“死去”的PyListObject。感谢党,感谢政府,又给它们一个重新做“人”的机会:)但是,需要指出,这里缓冲的仅仅是PyListObject对象,而没有这个对象曾经拥有的PyObject*列表,因为这些PyObject指针的引用计数已经减少了,这些指针所指的对象都要各奔前程,或生存,或毁灭,不再被PyListObject所给与的那个引用计数所束缚。PyListObject如果继续维护一个指向这些对象的指针的列表,就可能产生悬空指针的问题。所以,PyObject*列表所占用的空间必须归还给系统。
看一下我们刚刚创建的PyListObject的最后归宿:
在下一次创建PyListObject时,这个PyListObject将重新被唤醒,重新分配PyObject*列表占用的内存,重新拥抱新的对象。放眼四周,曾经所拥有过的那些对象,有的已经容颜苍老,有的已经烟消云散,是否有一种“无私人非事事休,欲语泪先流”的感慨呢?:)
4. Hack PyListObject
首先我们来观察在PyListObject中维护的元素数量变化时,PyListObject中ob_size和allocated两个变量的变化情况,从中窥见PyListObject对内存的使用和管理。
在PyListObject的输出操作list_print中,我们添加了如下代码,以观察PyListObject对内存的管理:
printf("/nallocated=%d, ob_size=%d/n", op->allocated, op->ob_size);
观察结果如图9所示:
首先创建一个包含一个元素的list,这时ob_size和allocated都是1。这时list中拥有的所有内存空间都已被使用完,所以下次插入元素时就一定会调整list的内存空间了。
随后向list末尾追加元素2,可以看到,调整内存空间的动作发生了。allocated变成了5,而ob_size则变成了2,这里明确地显示出了PyListObject所采用的与C++中vector一样的内存缓冲池策略。
继续向list末尾追加元素3,4,5,当追加了元素5之后,list所拥有的内存空间又被使用完了,下一次再追加或插入元素时,内存空间调整的动作又会再一次发生。
如果这时在list中删除元素3,可以看到,ob_size发生了变化,而allocated则不发生变化,它始终如一地维护着当前list所拥有的全部内存数量。
接下来我们从图10的结果中观察一下PyListObject对象的创建和删除对于Python维护的PyListObject对象缓冲池的影响。
这次为了消除Python交互环境执行时对PyListObject对象缓冲池的影响,我们通过执行py脚本文件来观察,可以看到,当创建新的PyListObject对象时,如果缓冲池中有可用的PyListObject对象,则会使用缓冲池中的对象;而在销毁一个PyListObject对象时,确实将这个对象放到了缓冲池中。
- Python源码剖析[11] —— PyListObject对象(3)
- Python源码剖析[9] —— PyListObject对象(1)
- Python源码剖析[10] —— PyListObject(2)
- Python源码剖析[3] —— 整数对象(1)
- Python源码剖析[5] —— 整数对象(3)
- Python源码剖析[8] —— 字符串对象(3)
- Python源码剖析[14] —— 字典对象PyDictObject(3)
- python源码剖析笔记1——Python对象初见
- Python源码剖析[12] —— 字典对象PyDictObject(1)
- Python源码剖析[2] —— 对象机制
- Python源码剖析[4] —— 整数对象(2)
- Python源码剖析[6] —— 字符串对象(1)
- Python源码剖析[7] —— 字符串对象(2)
- Python源码剖析[13] —— 字典对象PyDictObject(2)
- [笔记]PyListObject对象
- 《Python 源码剖析》之对象
- 《python源码剖析》笔记 python对象初探
- Python源码剖析(02 Python对象初探)
- 用命令行参数启动自动部署应用程序
- 服务器安全配置技巧--高级篇
- Python源码剖析[8] —— 字符串对象(3)
- Python源码剖析[9] —— PyListObject对象(1)
- Python源码剖析[10] —— PyListObject(2)
- Python源码剖析[11] —— PyListObject对象(3)
- [转贴]民族乐器--阮
- Python源码剖析[13] —— 字典对象PyDictObject(2)
- Python源码剖析[14] —— 字典对象PyDictObject(3)
- Python源码剖析[15] —— 最简单的Python实现:Small Python
- const使用详解
- 代理服务器
- 设计为王
- 这个学期过完了,总结一下(工程篇)