• Python GC


    python的垃圾收集是引用计数的补充,所以它的工作原理和教科书上的mark-sweep有着不同——它会用到引用计数的值;进入垃圾收集的对象都是容器(可包含 PyObject 的对象,它们必须提供 tp_traverse 函数实现);它没有直接的 root object,(传统的流程是直接将 root object 放入unscaned 队列,然后一个收集周期就开始了),经过 subtract_refs(young) 后才找到 root object

    python 垃圾分为三代(非增量)

    /* 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},
    };

    threshold 对 0 代的含义为 700 个对象分配;对 1,2 代对象的含义为 10 次上代对象的垃圾收集

    查看 gcmodule.c 的 collect 函数即可一窥 python 收集机制的全貌,如下:

        PyGC_Head *young; /* the generation we are examining */
        PyGC_Head *old; /* next older generation */
        PyGC_Head unreachable; /* non-problematic unreachable trash */
        PyGC_Head finalizers;  /* objects with, & reachable from, __del__ */

    以上都是双向循环链表

        /* merge younger generations with one we are currently collecting */
        for (i = 0; i < generation; i++) {
            gc_list_merge(GEN_HEAD(i), GEN_HEAD(generation));
        }

    将更年轻的代,合并到需要收集的代里面

        /* Using ob_refcnt and gc_refs, calculate which objects in the
         * container set are reachable from outside the set (i.e., have a
         * refcount greater than 0 when all the references within the
         * set are taken into account).
         */
        update_refs(young);
        subtract_refs(young);


    将GC头的gc_refs设置为引用计数的值

    然后将遍历链表,对每个对象调用 traverse 遍历对象所包含的子对象,将对象所包含的子对象的gc_refs值减1


    结果:

    对象 gc_refs == 0 表示此对象仅被本集合(需要收集的代以及更年轻的代)的对象包含(注意:并不表示该对象为垃圾,可以直接删除)

    对象 gc_refs > 0 表示此对象被集合外的对象所包含

        /* Leave everything reachable from outside young in young, and move
         * everything else (in young) to unreachable.
         * NOTE:  This used to move the reachable objects into a reachable
         * set instead.  But most things usually turn out to be reachable,
         * so it's more efficient to move the unreachable things.
         */
        gc_list_init(&unreachable);
        move_unreachable(young, &unreachable);

    将不可达对象移入unreachable。

    实现是这样的,从young开始往后走,到young为止(前面提到过的,young是循环链表):

    1)将 gc_refs == 0 的对象移入 unreachable;

    2)对 gc_refs > 0 的对象调用 traverse 遍历对象所包含的子对象,如果子对象在unreachable中,则将该对象插入 young 的前面并将该对象 gc_refs=1


    如果觉得上面一个循环干的事太杂,想不明白。则可以这么理解:首先,gc_refs == 0 的对象移入 unreachable,young则只剩下 gc_refs > 0的对象;接着,就是传统mark-sweep的作法了, young 为 root object……

        /* Leave everything reachable from outside young in young, and move
         * everything else (in young) to unreachable.
         * NOTE:  This used to move the reachable objects into a reachable
         * set instead.  But most things usually turn out to be reachable,
         * so it's more efficient to move the unreachable things.
         */
        gc_list_init(&unreachable);
        move_unreachable(young, &unreachable);
    
        /* Move reachable objects to next generation. */
        if (young != old) {
            if (generation == NUM_GENERATIONS - 2) {
                long_lived_pending += gc_list_size(young);
            }
            gc_list_merge(young, old);
        }
        else {
            long_lived_pending = 0;
            long_lived_total = gc_list_size(young);
        }

    合并前面步骤找到的可达对象至更老的一代(如果存在更老的代)

        /* Call tp_clear on objects in the unreachable set.  This will cause
         * the reference cycles to be broken.  It may also cause some objects
         * in finalizers to be freed.
         */
        delete_garbage(&unreachable, old);

    释放对象(实现里面有个小技巧,先自增容器的引用计数,清空容器——会对包含的子对象们减引用计数,接着再减容器的引用计数)

  • 相关阅读:
    Linux 进程退出后自动启动
    Python UDP broadcast PermissionError: [Errno 13] Permission denied
    C# 获取MAC地址
    C# 多线程
    C# UdpClient 设置超时时间
    C# 控件聚焦
    C# 添加图片资源
    C# Listview 第一列不能居中
    Ubuntu 14.04 AM335x TI-RTOS 编译
    为AM335x移植Linux内核主线代码
  • 原文地址:https://www.cnblogs.com/JesseFang/p/2773504.html
Copyright © 2020-2023  润新知