【Python】简述Python的垃圾回收机制


参考文章

Python的垃圾回收机制主要是以引用计数为主,标记清除和分代回收为辅。

一、引用计数

每个对象维护着一个ob_ref变量,用来统计当前对象被引用的次数,也就是用来追踪到底有多少个引用指向了这个对象。当发生以下4种情况时,对象的引用计数加1。

  1. 对象被创建,如 a = 1
  2. 对象被引用,如 b = a
  3. 对象被当做参数传入一个函数中,如func(a)
  4. 对象被当做元素存储在容器中时,如li = [a, 2, 3]

与上述情况相对应,当出现以下4种情况时,对象的引用计数减1。

  1. 对象被显示销毁,del a
  2. 当该对象的引用别名被赋予了新的对象,如 b = 2
  3. 当对象离开它的作用域,如函数执行完毕。
  4. 当对象从容器中移除,或者容器被销毁时。

引用计数的优点:

  1. 高效性
  2. 实时性
  3. 易于实现

引用计数的缺点:

  1. 维护引用计数需要消耗额外的资源
  2. 无法解决循环引用的问题。例如:
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

为了弥补引用计数GC机制的上述两个缺点,Python还引入了以下两种GC机制。

二、标记清除

标记清除(Mark—Sweep)算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢?
对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

三、分代回收

gc逻辑

分配内存
-> 发现超过阈值了
-> 触发垃圾回收
-> 将所有可收集对象链表放到一起
-> 遍历, 计算有效引用计数
-> 分成 有效引用计数=0 和 有效引用计数 > 0 两个集合
-> 大于0的, 放入到更老一代
-> =0的, 执行回收
-> 回收遍历容器内的各个元素, 减掉对应元素引用计数(破掉循环引用)
-> 执行-1的逻辑, 若发现对象引用计数=0, 触发内存回收
-> python底层内存管理机制回收内存

分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值