use*_*262 33 python garbage-collection cpython
我试图了解Python的垃圾收集器如何检测循环引用.当我查看文档时,我看到的只是一个声明,即检测到循环引用,除非涉及的对象有__del__方法.
如果发生这种情况,我的理解(可能是错误的)是gc模块通过(我假设)遍历所有分配的内存并释放任何无法访问的块来充当故障保护.
在使用gc模块之前,Python如何检测和释放循环内存引用?
Dav*_*ver 26
在使用gc模块之前,Python如何检测和释放循环内存引用?
它没有.gc仅用于检测和释放循环引用.非循环引用通过引用计数来处理.
现在,要了解 gc 如何确定任何给定对象引用的对象集,请查看中的gc_get_references函数Modules/gcmodule.c.相关的一点是:
// Where `obj` is the object who's references we want to find
traverseproc traverse;
if (! PyObject_IS_GC(obj))
continue;
traverse = Py_TYPE(obj)->tp_traverse;
if (! traverse)
continue;
if (traverse(obj, (visitproc)referentsvisit, result)) {
Py_DECREF(result);
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
这里的主要功能是tp_traverse.每个C级类型定义一个tp_traverse函数(或者对于不包含任何引用的对象,例如str,将其设置为NULL).一个例子tp_traverse是list_traverse,遍历函数list:
static int
list_traverse(PyListObject *o, visitproc visit, void *arg)
{
Py_ssize_t i;
for (i = Py_SIZE(o); --i >= 0; )
Py_VISIT(o->ob_item[i]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我看到的是一个声明,即检测到循环引用,除非涉及的对象有
__del__()方法.
你是对的 - Python的循环检测器可以检测和收集循环,除非它们包含带有__del__方法的对象,因为解释器无法安全地删除这些对象(为了直观了解为什么这样,想象你有两个对象使用__del__相互引用的方法.它们应该以哪种顺序被释放?).
当__del__一个循环中涉及带有方法的对象时,垃圾收集器会将它们粘贴在一个单独的列表中(可访问gc.garbage),以便程序员可以手动"处理"它们.
在使用gc模块之前,Python如何检测和释放循环内存引用?
Python的垃圾收集器(实际上不是gc模块,这只是垃圾收集器的Python接口)执行此操作。因此,Python 在使用垃圾收集器之前不会检测并释放循环内存引用。
通常,Python通常会在大多数对象的引用计数达到零时释放它们。(我之所以说“大多数”,是因为它从不释放小整数或内联字符串)。在循环引用的情况下,这永远不会发生,因此垃圾收集器会定期遍历内存并释放循环引用的对象。
当然,这都是CPython特有的。其他Python实现具有不同的内存管理(Jython = Java VM,IronPython = Microsoft .NET CLR)。
我想我在@SvenMarnich提供的一些链接中找到了我正在寻找的答案:
Container对象是可以保存对其他Python对象的引用的Python对象.列表,类,元组等是容器对象; 整数,字符串等不是.因此,只有容器对象存在循环引用的风险.
每个Python对象都有一个字段 - *gc_ref*,对于非容器对象,它(我相信)设置为NULL.对于容器对象,将其设置为等于引用它的非容器对象的数量
*gc_ref*计数大于1的任何容器对象(?我认为0,但现在好吗?)的引用不是容器对象.因此它们是可达的,并且从考虑不可达的存储器岛中移除.
已知可达的对象可以访问的任何容器对象(即我们刚刚识别为具有大于1的*gc_ref*计数的对象)也不需要被释放.
剩余的容器对象不可访问(彼此除外),应该被释放.
http://www.arctrix.com/nas/python/gc/是一个提供更全面解释 的链接http://hg.python.org/cpython/file/2059910e7d76/Modules/gcmodule.c是一个链接到源代码,其中有评论进一步解释了循环参考检测背后的想法