Giter Site home page Giter Site logo

Comments (6)

zpoint avatar zpoint commented on May 12, 2024

b 在 unreachable 中而不是 finalizers 中, 你截取的代码是处理 finalizers 而不是处理 unreachable 的, 我们可以只关注处理 unreachable 的部分

通常情况下 finalizers 列表为空

finalizers 存储的是定义了 老式的析构函数 的对象, python3.4 以后的 析构函数(默认的__del__) 是映射到 C语言中的结构体中的 tp_finalize 字段上的, 而之前的版本是 映射到了 tp_del 字段上, 所以只有以前写的 C 扩展定义了 tp_del 的对象在进行垃圾回收时, 才有可能进到 finalizers 中, 默认情况下 finalizers 就是空的, 你上面截出的函数把它放到 gc.garbage 列表中不进行处理是对的(参考 PEP 442)

unreachable 中的对象 b 在 finalize_garbage(&unreachable); 中调用了 __del__ 之后就变成可达对象了, 会导致在 if (check_garbage(&unreachable)) 判断为真, 本轮 a1, a2, a3, b 都不回收, 下一轮回收时 a1, a2 就被正常回收, a3, b 不回收

from cpython-internals.

Panlq avatar Panlq commented on May 12, 2024

finalize_garbage(&unreachable)中的代码 实现了__del__的对象 引用计数会加1, 且如您所说 _gc_prev 上的第一个 bit flag 会被设置, a3, b 不回收,这么说的话 a3, b 会一直在内存中? 并没有被回收,在官方文档也看到官方警告 也不推荐使用__del__方法,当解释器退出时不会确保为仍然存在的对象调用 del() 方法。
还有一个疑惑,官方文档说在 3.4 版更改: 根据 PEP 442 ,带有 del() 方法的对象最终不再会进入 gc.garbage ,但就上面代码来看

/* Handle uncollectable garbage (cycles with tp_del slots, and stuff reachable
 * only from such cycles).
 * If DEBUG_SAVEALL, all objects in finalizers are appended to the module
 * garbage list (a Python list), else only the objects in finalizers with
 * __del__ methods are appended to garbage.  All objects in finalizers are
 * merged into the old list regardless.
 * Returns 0 if all OK, <0 on error (out of memory to grow the garbage list).
 * The finalizers list is made empty on a successful return.
 */

If DEBUG_SAVEALL, all objects in finalizers are appended to the module

  • garbage list (a Python list), else only the objects in finalizers with
  • del methods are appended to garbage.

这里是不是有点冲突了?

from cpython-internals.

zpoint avatar zpoint commented on May 12, 2024

官方警告似乎没有看到 不推荐使用 __del__ 方法的表述?

示例代码 中当前的 namespace 中有 a3, a3 里面有 b, 那么只要我还保留着 a3 的引用, a3 和 b 就会一直在内存中, 如果我不需要 a3 了, 下一轮垃圾回收的时候 a3 和 b 就会回收

你贴的这段代码注释(按我)理解是 finalizers 中的所有对象中只有自定义了 __del__ 方法的对象会被放到 gc. garbage 中, 如果你开启了 gc.set_debug(gc.DEBUG_SAVEALL) 开关的话, finalizers 中所有的对象(即使没有自定义__del__ )也会被放到 gc. garbage

但是你为什么要一直纠结 finalizers 这个列表呢

b 显式的定义了 __del__, b 在 unreachable 这个列表中, 不在 finalizers
a1, a2, a3 都没有定义 __del__, a1, a2, a3 也还是在 unreachable 这个列表中, 不在 finalizers
所以不论定义没定义 __del__, 这些对象都只可能出现在 unreachable 列表中, 不会出现在 finalizers
finalizers 列表从开始到结束都是空列表

finalizers 的作用是把 以前用 C 写的扩展中老代码定义了 __del__ 方法的对象放到 gc.garbage 中, 对这一部分对象, 延用的还是旧的不回收的处理方式

我猜测你想找的应该是处理 unreachable 这个列表的代码, 但是你找到了 finalizers 上面去了, 如果是这种情况的话你可以在中间加一些日志代码, 自己编译运行调试一下😁

from cpython-internals.

Panlq avatar Panlq commented on May 12, 2024

恩恩,明白了
finalizers 的作用是把 以前用 C 写的扩展中老代码定义了__del__方法的对象放到 gc.garbage 中, 对这一部分对象, 延用的还是旧的不回收的处理方式。
明白了,还是要编译运行调试一下,就可以知道结果了,感谢大佬不吝指教,谢谢~

from cpython-internals.

Panlq avatar Panlq commented on May 12, 2024

有个疑惑请大神解答一下,在处理循环引用的时候,是如何判断是不是要对该对象进行gc_ref-=1的操作的?
subtract_refs 会遍历 young 中的所有对象, 对于每个对象, 检查当前对象身上所引用到的所有其他对象, 这些其他对象如果也在 young 中, 并且是可回收的对象, 把这个对象复制到 _gc_prev 的引用计数部分减1 (用 tp_traverse 遍历, 遍历回调函数为 visit_decref)
请问这句话怎么理解呢:检查当前对象身上所引用到的所有其他对象, 这些其他对象如果也在 young 中, 并且是可回收的对象?
看您的图是把young里的gc_ref都进行了减1操作,然后对于c 和 d2又进行了加一操作(我在其他文章看到说这协变量是root object)所以会检查当前变量是不是root object 如果是且被添加到了unreachable中,就将其gc_ref+1 , 并添加回yong中。

from cpython-internals.

zpoint avatar zpoint commented on May 12, 2024
/*
假设
A = [B, C, D]
A在代内, B也在代内, C不在, D不在
遍历A引用的对象, B在代内, B进行 gc_ref-=1
C不在, 不进行 gc_ref-=1
D不在, 不进行 gc_ref-=1
同一个代里, 对象的所有互相的引用都会触发 gc_ref-=1
下面这段代码就是你上面高亮文字部分
 */
static void
subtract_refs(PyGC_Head *containers)
{
    traverseproc traverse;
    PyGC_Head *gc = GC_NEXT(containers);
    for (; gc != containers; gc = GC_NEXT(gc)) {
        PyObject *obj = FROM_GC(gc); // #define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
        visit_from = obj;
        traverse = Py_TYPE(FROM_GC(gc))->tp_traverse;
        (void) traverse(FROM_GC(gc),
                       (visitproc)visit_decref,
                       NULL);
    }
}

cd2subtract_refs 之后被减到了小于等于 0

static void
move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
{
    // ...
    while (gc != young) {
        PyObject *obj = FROM_GC(gc); // #define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))

        if (gc_get_refs(gc)) {
            /* 
            遍历到 namespace 的时候, 由于 namespace 还保存了 `c` 和 `d2` 的引用
            visit_reachable 会把 `c` 和 `d2` 的引用计数置为 1
             */
            PyObject *op = FROM_GC(gc);
            traverseproc traverse = Py_TYPE(op)->tp_traverse;
            // ...
            visit_from = op;
            (void) traverse(op,
                    (visitproc)visit_reachable,
                    (void *)young);
            // ...
        }
        else {
            // ...
        }
        // ...
        gc = (PyGC_Head*)prev->_gc_next;
   }
}

cd2move_unreachable 之后被重置为 1

from cpython-internals.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.