python的垃圾回收机制

本文详细阐述了Python中的垃圾回收机制,包括引用计数器原理、环状双向链表refchain的应用,以及为解决循环引用问题引入的标记清除和分代回收策略。通过四个维护的链表管理对象生命周期,确保内存有效利用和避免内存泄漏。
摘要由CSDN通过智能技术生成

python的垃圾回收机制

内容整理自视频https://www.bilibili.com/video/BV1F54114761?p=2&spm_id_from=pageDriver

       引用计数器为主,标记清除和分代回收为辅助.

1.应用计数器

1.1 环状的双向链表 refchain

在python程序中,创建的任何对象都会放在refchain中.

当创建 #name='xxx'时, python 内部会通用创建一些数据

[上一个对象,下一个对象,类型,引用个数]

不同数据类型会创建一个相对的值

Age=18 会创建

[上一个对象,下一个对象,类型,引用个数,val=18]

列表 会创建

[上一个对象,下一个对象,类型,引用个数,items=元素,元素个数]

底层源码

在C源码中体现每个对象中都有的相同的值:PyObject结构体(4个值:上一个,下一个,类型,引用个数)

体现由多个元素组成的对象:PyObject结构体(4个值)+ob_size.至少封装五个值.

1.2 详细解析类型封装结构体

屏幕剪辑的捕获时间: 2021/4/19 20:50

1.3引用计数器

V1=3.14

V2=999

V3=(1,2,3)

  当python程序运行时 会根据数据类型的不同找到其对应的结构体,根据结构体中的字段,创建相关的数据,然后将对象添加到refchain双向链表中.

  源码中有两个关键的结构体:PyObject(公共)和PyVarObject(多个元素).

  每一个对象中 都有 ob_refcnt 就是引用计数器,默认为1,当有其他变量引用该对象时,则引用计数器会发生变化

加一:a=33,b=a 则a的引用计数器 加一

减一:del b   则a的引用计数器 减一

  当引用计数器为0时,意味着改对象不再被使用了,则证明该对象为垃圾,然后进行回收,

  回收:1.将对象从refchain移除,2.将对象进行销毁,将内存归还给系统

1.4引用计数器的循环引用问题

循环引用 交叉感染

执行append后 v1 v2 的引用计数器 值均为2

执行del后   v1 v2 的应用计数器 均为1

则 v1 v2 永远不会被销毁,

这样的代码多了,内存会被沾满,发生爆栈,内存泄露.重启可以解决

2.标记清除

  目的:为了解决引用计数器的循环引用不足.

  实现:在python底层 再维护一个链表,链表中专门放那些可能存在循环引用的对象(列表,字典,元组,集合)

    在python内部,某种情况下触发,扫描可能存在循环引用的链表中的每一个元素,检查是否有循环引用,如果有则让双方的引用计数器都减一,如果为0,则是垃圾,进行回收.

会有两个问题发生

     1.我们不知道什么时候扫描

     2.扫描代价大.每次扫描耗时久.

3.分代回收

四个链表搞定一切

1.将可能存在循环引用的对象,维护成3个列表:

0代:0代中的对象个数达到700个则扫描一次0代,

1代:0代扫描10次,1代扫描一次,

2代:1代扫描10次,2代扫描一次.

  扫描过程中,引用计数器减一,如果引用计数器为0,则是垃圾,进行回收.

  如果不是垃圾,则从0代升级到1代.只有0代阈值是对象个数,1代,2代都是前代的扫描次数

4.小结

  在python中,维护了一个refchain的双向环状链表,这个链表中存储程序中创建的所有对象,

  每种类型对象中都有一个ob_refcnt的引用计数器值.当有引用时,引用计数器的值加一,有删除时

  引用计数器的值会减一,当引用计数器的值,变为0时,进行垃圾回收(对象销毁,refchain中移除).

  但是,在python中,对于那些可以有多个元素组成的对象可能存在循环引用的问题,为了解决这个问题,python又引入了标记清除和分代回收,在其内部,共维护四个链表,分别是:

      1.refchain 维护所有对象的

      2.2代      2代扫描10次扫描一次

     3.1代      0代扫描10次扫描一次

     4.0代     当存储达到700个对象时扫描

  在源码内部,当达到各自的阈值时,会触发扫描链表,进行标记清除的动作(有循环引用,则格子减一)

   但是,在源码内部在上述的流程中提出了优化机制.

5.Python缓存 详见

https://pythonav.com/wiki/detail/6/88/

  5.1 池(int类型,字符串)

   为了避免重复创建和销毁一些常见对象,维护一个池,

    假设创建 a=7,b=9, 按理说 会创建两个对象 放入refchain中, 但实际是

   在python解释器启动时候,帮我们自动创建 -5到256的值全部创建.

   在程序执行a=7时,不会开辟新内存了,直接去池里取.

  

  5.2free_list机制(float/list/tuple/dict)

当一个对象引用计数器为0时,按理说应该回收,实际内部并不会回收,而是将对象

  而是将对象添加到 free_list链表中当缓存.以后再去创建对象时,不会重新开辟内存

  而是直接使用free_list

Free_list 会有缓冲大小 list和dict最多缓存80个对象.tuple最多缓存20个对象

str有自己的unicode_latin1[256]链表 将所有的ascii字符缓存起来.

字符串 有助流机

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扁舟钓雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值