0
点赞
收藏
分享

微信扫一扫

4.浅谈Python垃圾回收机制

E_topia 2022-04-13 阅读 63

垃圾回收机制初接触

1.所谓的垃圾是什么呢?

在我们日常生活当中会产生各种各样的垃圾,比如说生活垃圾,然后有害垃圾,还有一些垃圾人…

那我们肯定就是将它们放到对应的分类,然后有人在固定的时候将它们回收掉。然后进行废物利用吧啦吧啦的…

2.Python的垃圾回收机制

那么在Python当中也有这么一个垃圾回收机制,但是Python当中的垃圾回收机制是采用的 引用标记 ,那么可能就有人问了什么是引用标记呢?

  • 引用标记
    指的就是通过变量值去绑定变量名的过程叫引用标记

当我通过变量值绑定的变量名 增加 了,这就叫 引用计数增加
那么相反,我解除了他们之前的绑定关系,这就叫 引用计数减少
当被绑定的变量名为0时,该变量值无法被访问的到,就被称为 垃圾

3.引用计数的作用

当有变量值绑定到变量名的时候,这个时候就存在了引用间的绑定关系,所以增加跟减少都会对其造成影响

  • 引用计数增加

就像搞医学研究的,一组里面有a,b,c,d 四个人。四个人共用一只小兔子,我们可以把兔子理解为变量值,a,b,c,d为变量名那么现在变量值的引用计数就为四 ,因为有四个变量名在使用这个变量值,那么现在e也来用这只小白兔,那么就是五个人同时用一只兔子了,随着人变多了,对应的引用技术也就增加了

# 引用计数增加
x = 10  # 10的引用计数为1
y = x  # 10的引用计数为2
z = x  # 10的引用计数为3
  • 引用计数减少

那现在四个人里面,c、d被人叫走了要去做其他试验,跑路了,那么现在的引用计数就只剩下了a、b、e ,跑路了则说明他的引用计数减少了,所以当前对小白兔的引用计数就变成了3。

# 引用计数增加
x = 10  # 10的引用计数为1
y = x  # 10的引用计数为2
z = x  # 10的引用计数为3

# 引用计数减少
del x  # 解除变量名x与值10的绑定关系,10的引用计数变量为2
# print(y)
del y  # 10的引用计数为1
# print(z)
z = 12345  # 10的引用计数为0  这个时候原来的10就已经没有变量名可以访问到了,就变成了垃圾需要被清除
print(z)

4.标记清除

标记清除这个概念设计到的就是变量名的相互引用

关于变量的存储,内存中有两块区域:堆区与栈区,在定义变量时,变量名与值内存地址的关联关系存放于栈区,变量值存放于堆区,内存管理回收的则是堆区的内容,详解如下图,

定义了两个变量x = 10、y = 20

在这里插入图片描述

当我们执行x=y时,内存中的栈区与堆区变化如下

在这里插入图片描述
标记/清除算法的做法是当应用程序可用的内存空间被耗尽的时,就会停止整个程序,然后进行两项工作,第一项则是标记,第二项则是清除

  • 标记
    可以看做是从堆区中牵一根绳子到栈区当中,栈区当中一个内存地址可以被多个堆区中的身子牵着,只要是被牵住了那就不管在什么地方都能访问到。

    我们用不同的变量名去引用变量值,这就是间接引用,不管什么数据类型,只要可以引用到该变量值,就存在引用增加。当然直接引用跟间接引用都可以访问到数据。

  • 清除
    清除的过程将遍历堆中所有的对象,将没有标记存活的对象全部清除掉。也就是身子的一头没人牵着了,就像去遛狗,主人跑了然后就有狗贩子把狗偷了也是一个概念

直接引用指的是从栈区出发直接引用到的内存地址,间接引用指的是从栈区出发引用到堆区后再进一步引用到的内存地址,以我们之前的两个列表l1与l2为例画出如下图像

在这里插入图片描述

当我们同时删除l1与l2时,会清理到栈区中l1与l2的内容
在这里插入图片描述
这样在启用标记清除算法时,发现栈区内不再有l1与l2(只剩下堆区内二者的相互引用),于是列表1与列表2都没有被标记为存活,二者会被清理掉,这样就解决了循环引用带来的内存泄漏问题。

5.分代回收

分代回收可以这么理解,分为三个阶段,每个阶段数据达到的阈值都不一样,只要超过了阈值上线就会进入下一个阶段,直到最后阶段才停止。

背景:

基于引用计数的回收机制,每次回收内存,都需要把所有对象的引用计数都遍历一遍,这是非常消耗时间的,于是引入了分代回收来提高回收效率,分代回收采用的是用“空间换时间”的策略。

分代:

分代回收的核心思想是:在历经多次扫描的情况下,都没有被回收的变量,gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低,具体实现原理如下:

分代指的是根据存活时间来为变量划分不同等级(也就是不同的代)

新定义的变量,放到新生代这个等级中,假设每隔1分钟扫描新生代一次,如果发现变量依然被引用,那么该对象的权重(权重本质就是个整数)加一,当变量的权重大于某个设定得值(假设为3),会将它移动到更高一级的青春代,青春代的gc扫描的频率低于新生代(扫描时间间隔更长),假设5分钟扫描青春代一次,这样每次gc需要扫描的变量的总个数就变少了,节省了扫描的总时间,接下来,青春代中的对象,也会以同样的方式被移动到老年代中。也就是等级(代)越高,被垃圾回收机制扫描的频率越低

回收:

回收依然是使用引用计数作为回收的依据

在这里插入图片描述
虽然分代回收可以起到提升效率的效果,但也存在一定的缺点:

例如一个变量刚刚从新生代移入青春代,该变量的绑定关系就解除了,该变量应该被回收,但青春代的扫描频率低于新生代,所以该变量的回收就会被延迟。

  • 部分内容参考:
    https://zhuanlan.zhihu.com/p/108683483
举报

相关推荐

0 条评论