python 垃圾回收

发布时间 2023-08-19 22:10:45作者: 你说夕阳很美

【第1题】 Pythonn内存管理以及垃圾回收机制 - 武沛齐 - 博客园 (cnblogs.com)

https://www.bilibili.com/video/BV1F54114761/

 

 元祖

 总结:

为了回收内存,每个对象都加入了refchain双向环向链表,对象被引用+1,del掉-1,等于0内存就被回收,这个叫引用计数器ob_refcnt;但是像列表这种互相引用的,会出现循环引用问题。导致计数器不为0的情况,内存无法回收。所以出现了标记清除。

再维护一个链表,把可能存在循环引用(list,tuple,dict,set)的放入这个链表里,集中管理。某种清理下,出发扫描,然后是引用计数器那一套。但是扫描比较耗时,所以把标记清除一个链表拆分成3个,谓之曰分代回收。

不需要标记清除的链表,而是再维护三个链表0代,1代,2代。这个三个链表出发机制是,先0代,对象存refchain的时候,也放一份到0代里,当0代里的对象数量达到700及时,出发内存回收。0代执行10次才会执行一次1代。1代执行10次才会执行一次2代。

以上就是引用计数器,标记清除和分代回收的概念。引用计数器是最核心和根本的,而分代回收是标记清除的具体实现和优化。所以最后维护了4个链表,refchain、0代、1代和2代。这里强调一下,refchain放的是所有对象。

进一步优化就是后面的缓存机制:池和free_list。都是为了避免常用对象重复创建和销毁的。

顺带提一下,对象底层实现:Python中所有类型创建对象时,底层都是与PyObject和PyVarObject结构体实现,一般情况下由单个元素组成对象内部会使用PyObject结构体(float)、由多个元素组成的对象内部会使用PyVarObject结构体(str/int/list/dict/tuple/set/自定义类),因为由多个元素组成的话是需要为其维护一个 ob_size(内部元素个数)。

  • 2个结构体
    • PyObject,此结构体中包含3个元素。
      • _PyObject_HEAD_EXTRA,用于构造双向链表。
      • ob_refcnt,引用计数器。
      • *ob_type,数据类型。
    • PyVarObject,次结构体中包含4个元素(ob_base中包含3个元素)
      • ob_base,PyObject结构体对象,即:包含PyObject结构体中的三个元素。
      • ob_size,内部元素个数。