python垃圾回收机制(GC)

概述

Python 垃圾回收机制(Garbage Collection)主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上使用“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题;使用“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。

引用计数(reference counting)

要了解引用计数,我们有必要先了解一下PyObject。我们都知道Python中一切皆对象,全部对象都有一个共同的基类。Python内部使用了一个PyObject结构体来保存全部对象共同的数据成员,以及实现GC机制所需要的一些辅助字段(划重点)等。

我们深入到源码看看PyObject是什么:

 typedef struct_object {
 int ob_refcnt;
 struct_typeobject *ob_type;
 } PyObject;

(不用惊讶底层源码是C语言,因为Python(至少CPython)就是用C语言实现的~)
言归正传,我们可以看到PyObject中有个int型变量ob_refcnt,它就是用来做引用计数的。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。当引用计数为0时,该对象就会立即被回收,分配给该对象的内存就会释放出来。

引用计数的优点

  1. 简单 :只需要更新变量ob_refcnt的值即可
  2. 实时性 :一旦某个对象没有了引用,内存就直接释放了,不用像其他机制等到特定时机才释放内存。

引用计数的缺点

  1. 维护引用计数消耗资源 :需要额外的空间维护引用计数
  2. 循环引用 :导致内存泄漏

由于 循环引用带来的问题要更严重,所以下面单独说明,先看代码:

list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

list1与list2是相互引用的,即使不存在其他对象对它们的引用,list1与list2的引用计数也将持续为1,它俩所占用的内存永远无法被回收,这将是致命的。
对于如今的硬件条件,消耗资源尚且还能接受,但是循环引用会导致内存泄露,这是我们要极力避免的。为了解决对象的循环引用问题,Python还引入了标记-清除和分代回收两种机制。


标记-清除(mark and sweep)

标记清除算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。

对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(全局变量、调用栈、寄存器等)出发,沿着有向边遍历对象,将可到达的对象标记为活动对象,不可到达的对象就是要被清除的非活动对象。
这里写图片描述
在上图中,我们从根节点出发,可到达的有对象1、对象2、和对象3,但是对象4和对象5是不可达的,那么1、2、3就是活动对象,4和5是非活动对象即将被回收。


分代回收(generation collection)

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


参考:伯乐在线

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值