Python进阶-垃圾回收

本文介绍了Python的垃圾回收机制,主要包括引用计数、标记-清除和分代回收。引用计数用于跟踪对象的引用,当引用计数为0时释放内存。标记-清除解决了容器对象的循环引用问题。分代回收通过不同代的策略提高垃圾回收效率,减少应用程序暂停时间。触发条件包括引用计数为0、达到阈值和手动调用gc.collect()。
摘要由CSDN通过智能技术生成


 因为现在的计算机内存比较富裕,所以写程序的时候不会太考虑垃圾回收这方面的知识。但是,出来混总是要还的,既然我们不断的向系统索要资源,那么还是要了解一下什么时候以及怎样把资源还回去

垃圾回收机制

Python中的垃圾回收是以引用计数为主,分代回收为辅

引用计数

 在Python中每一个对象的核心都是一个结构体PyObject,它的内部有一个计数器(ob_refcnt),程序在运行的过程中会实时的更新ob_refcnt的值,来反映当前对象的引用计数。当引用计数为0时,那么该对象所占的内存就会被系统释放掉

引用计数+1

  • 对象被创建, a = 1
  • 对象被引用, b = a
  • 对象被当做参数,传入到一个函数中, func(a)
  • 对象作为一个元素,存储在容器中, [a, b]

引用计数减一

  • 对象别名被显示销毁,del a
  • 对象别名被赋予新的对象, a = 2
  • 一个对象离开他的作用域
  • 对象所在的容器被销毁或者是从容器中删除对象

当指向该对象的内存的引用计数器为0的时候,该内存将会被Python虚拟机销毁

引用计数的优点

  • 高效
  • 实现逻辑简单
  • 具备实时性
  • 对象有确定的生命周期

引用计数的缺点

  • 虽然实现逻辑简单,但是实现较麻烦。每一个对象需要分配单独的内存来统计引用计数,这无形中加大了内存的负担,并且需要对引用计数进行维护,在维护的时候容易出错。
  • 在一些场景下,可能会比较慢。正常来说垃圾会比较平稳运行,但是当需要释放一个大的对象时,需要对引用的所有对象循环嵌套调用,而从可能会花费比较长的时间。
  • 循环引用。这是引用计数的致命伤,引用计数无法搞定。

标记-清除

 Python采用了标记-清除(Mark and Sweep)算法,解决容器对象可能产生的循环引用问题。

在进行垃圾回收时的步骤:

  • 标记阶段:遍历所有的对象,如果是可达的,也就是还有引用指向它,那么就标记该对象为可达
  • 清楚阶段:再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收

 标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用的问题。
 Python会使用一个双向链表将这些容器对象组织起来。不过标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只有一小部分的活动对象也要扫描所有对象。
标记-清除是为了解决循环引用问题。可以包含其他对象引用的容器对象都可讷讷个产生循环引用,为此,在申请内存时,所有容器头部会加上PyGC_Head来实现标记-清除机制。
任何一个Python对象都分为两部分:PyGC_Head + 对象本身数据
 而在对象申请内存的时候,实际申请的内存数量已经加上了PyGC_Head的大小

分代回收

 在循环引用对象的回收中,整个应用程序会被暂停,为了减少应用程序暂停的时间,Python通过分代回收(Generational Collection)以空间换时间的方法提高垃圾回收效率。
 对于陈新股,存在一定比例的内存块的生存周期比较短;而剩下的内存块,生存周期会比较长,甚至会从程序开始一直持续到程序结束。生存期较短对象的比例通常在80%~90%之间,这种思想简单点说就是:对象存在的时间越长,越可能不是垃圾,应该越少去收集。这样在执行``标记-清除`算法时可以有效减少遍历的对象数,从而提高垃圾回收的速度。

原理

 Python gc给对象定义了三种代(0,1,2),每一个新生对象在generation zero中,如果他在一轮gc扫描汇总活了下来,那么它将被移至generation one,再继续进行较少的扫描,如果它又活过了一轮gc,它又将被移至generation two,继续进行更少次数的扫描。

触发扫描

 当某一代中被分配的对象与被释放的对象之差达到某一阈值的时候,就会触发gc对某一代的扫描。

注意

 当某一代的扫描被触发时,比该代年轻的代也会被扫描。简单来说就是当代2的gc扫描被触发了,那么代0、代1也将被扫描,如果代1的gc扫描触发了,那么代0也会被扫描

触发条件

  • 被引用为0时,立即回收当前对象
  • 达到了垃圾回收的阈值,触发标记-清除
  • 手动调用gc.collect()
  • Python虚拟机退出的时候

总结

总体来说,在Python中,主要通过引用计数进行垃圾回收;通过标记-清除解决容器对象可能产生的循环引用问题;通过分代回收以空间换时间的方法提高垃圾回收效率。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值