python c++ 释放内存_29. 来,GC 内存都连成一个圈!

582f42f99393f15023ce903ad20c01c0.png

不是所有对象都有被 GC 照顾的殊荣,只有那些胸怀广大的 “容器” 才能被纳入 GC 的 “小圈圈”。我们已经直到所有在 GC 中的内存在创建之初,就被额外增加了一个包含 _gc_next_gc_prev 的两个指针,这俩兄弟显而易见是在维护一个双向链表。

为了找到这个链表的位置,我们首先顺着 _PyObject_GC_TRACK 一层层抽丝剥茧,看看一个对象是如何被追加到某个链表中的,最终在这里找到了:

// include/internal/pycore_object.h:27

每当 Python 创建一个新的容器对象,其会立刻被插入 GC 的 generation0 链表尾部,从代码中的插入操作来看,这是一个当前运行时(PyRuntime)中的双向链表。generation0 的结构看起来这样:

2afe290f768d1ef396d8dfc4c5276c6b.png
(图中指针指向的位置实际上都应该是内存的起始位置,为了方便简化为图中表示)

gc.generation0 的类型也是 GC_HEAD, 它充当了链表的头部和哨兵(sentinal)节点,这是一种典型的链表操作方法。Python 中利用双向链表将所有 GC 对象链接成一个环。

新创建的 GC 对象被链入了 gc.generation0,如果了解过常用 GC 算法就会想到,这里表示的是 “分代垃圾回收” 算法中的 0 代内存,那想必还有其他代内存了。这种直觉是正确的,可以在这里看到 Python 中内存分代的规划:

//Modules/gcmodule.c:128

可以清楚的看到, Python 采用了 3 代内存回收策略,其中 0 代的触发阈值是 700, 即 0 代对象超过 700 个就开始尝试回收内存,其他两代的阈值则是 10。使用分代垃圾回收策略的还有 C#、Java 等等,使用比较常见的垃圾回收策略,分代回收的主要目的是减少 GC 操作,提高虚拟机运行效率,其基本思想简而言之:

  • 年轻代来去匆匆;
  • 中老年安土重迁。

那些已经存在很久的对象更可能继续存在下去,刚创建的对象则很可能很快就被抛弃。

需要注意的是,Python 3.8 中 GC_HEAD 的两个指针在不同时刻可能被用来表示其他信息。

明天继续了。

关注我,了解程序员的烧脑日常,还有开源 Python 教程。

bea6233048fabac8af5e8b238f019f9f.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值