您当前的位置: 首页 >  Python

庄小焱

暂无认证

  • 1浏览

    0关注

    805博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Python——垃圾回收机制(3)

庄小焱 发布时间:2021-05-26 09:19:03 ,浏览量:1

摘要

主要是讲解的python中的垃圾回收机制原理,同时区分java中的垃圾回收机制的不同。Python的垃圾回收机制与Java还是存在着不小的差异的。首先在垃圾识别算法上,Python采用引用计数为主的操作方法。

  • Python使用引用计数为主的垃圾识别算法最关键的原因,在于Python是解释执行的脚本式语言。解释型的语言最大的特点是边解释,便执行,因此进行同步的对象引用计数操作就是顺利成章的事情了,能将计算分摊到整个程序运行的生命周期中,一旦对象没有引用后进行直接回收,整个程序收到的压力便会小很多,很适于脚本式语言的运行。但带来最显著的问题,就是极大的拖慢了程序运行的速度,因此我们不会对脚本类的语言性能有太高的要求。
  • 同时,为了解决循环依赖问题,Python语言使用另一种机制来辅助监测循环依赖情况。Python针对可能产生循环引用情况的变量,创造了两个链表:root链表和unreachable链表。root链表中存储被使用的变量对象,而unreachable链表负责存储即将被回收的“垃圾”变量对象。之所以这样做,是考虑到被放入unreachable链表内的对象还有被其他变量间接或直接引用的可能,如果被引用,则移入root链表内,然后对剩下的unreachable的变量进行回收。
  • 同时,在Python中也有分代回收机制,也主要是针对非即时回收的变量,但简单很多。Python往往会维护三个代的链表012,0代对象在第一次GC中存活,则移入1代,1代对象存活,再次经过GC存活,则移入2代。Python会对每代的GC时机设定阈值,当前一代的垃圾回收次数超过当前代的阈值,就会触发一次本代的垃圾回收,以最终实现垃圾回收的分代回收。
概述:

不同于C/C++,像Python这样的语言是不需要程序员写代码来管理内存的,它的GC(Garbage Collection)机制 实现了自动内存管理。GC做的事情就是解放程序员的双手,找出内存中不用的资源并释放这块内存。 下面我们来看看Python的GC是怎么做的:

Python自带的解释器CPython主要使用了三种垃圾回收机制(引用计数为主,标记-清除和分代回收为辅):

  • 引用计数
  • 标记清除
  • 分代回收

下面让我们分别了解下这几种机制:

1.引用计数

引用计数法Reference Counting的原理是,每个对象都维护一个引用计数字段,记录这个对象被引用的次数(如果不清楚变量->引用->对象 的问题,可以查看深拷贝与浅拷贝),如果有新的引用指向对象,对象引用计数就加一,引用被销毁时,对象引用计数减一,当用户的引用计数为0时,该内存被释放。可以通过sys.getrefcount()函数查看对象被引用的个数。

这种方法主要存在两种问题:

  • 需要去维护引用计数,存在执行效率问题
  • 无法解决循环引用问题

所谓循环引用就是:有一组对象的引用计数不为0,但是这组对象实际上并没有被变量引用,它们之间是相互引用,而且也不会有其他的变量再去引用这组对象,最终导致如果使用 引用计数法 这些对象占用的内存永远不会被释放。

a=[6666]
b =[8888]

a.append(b)
b.append(a)

print(a)
print(b)

得到的结果估计你们心中产生困惑,咋不报错呢:看下面

[6666,[8888,[...]]]
[8888,[6666,[...]]]

Process finished with exit code o

可以看到,现在a b都出现了循环引用,此时就算使用del语句删除变量,被使用的内存也不会被回收,所以就需要第二种GC机制:

2.标记清除

标记清除Mark-Sweep是针对循环引用问题的回收机制,作用的对象是容器类型的对象(比如:list、set、dict等)。原理是:通过根节点对象(不会被删除的对象)对有向图把所有活动对象打上标记,然后回收没有被标记的非活动对象。

原理:1. 寻找跟对象(root object)的集合作为垃圾检测动作的起点,跟对象也就是一些全局引用和函数栈中的引用,这些引用所指向的对象是不可被删除的;2. 从root object集合出发,沿着root object集合中的每一个引用,如果能够到达某个对象,则说明这个对象是可达的,那么就不会被删除,这个过程就是垃圾检测阶段;3. 当检测阶段结束以后,所有的对象就分成可达和不可达两部分,所有的可达对象都进行保留,其它的不可达对象所占用的内存将会被回收,这就是垃圾回收阶段。(底层采用的是链表将这些集合的对象连接在一起)

缺点:标记和清除的过程效率不高

3.分代回收

分代回收是建立在标记清除基础上的一种辅助回收容器对象的GC机制。 无论开发的程序类型如何,规模如何,都有这样的相同之处:一些比例的内存生存周期都很短,而另一些内存的生存周期比较长,可能会伴随着整个程序的开始和结束。 所以分代回收就根据系统中内存存活时间把它们划分成不同的集合:一共分成三个集合,每个集合称为一个代。 它们的垃圾收集频率 随 对象 存活存活时间的增大 而 减小。也就是说:对于存活时间越长的对象,就越不可能是垃圾,减少对其的收集频率。而新创建的对象都在第一代,第一代集合总数达到上限后,会触发GC机制:可以回收的对象所占的内存被释放,不能被回收的移到中年代。内部垃圾处理机制扫描不能被回收的产生新生代-----第一代集合总数达到上限后,会触发GC机制 将还继续被引用,移到中年代-----》》》时间周期变长,同样触发GC回收机制-----》》》老年代------》》》其实垃圾回收机制内部是咱们Cpython 解释器GIL全局锁的底层原理。

关注
打赏
1657692713
查看更多评论
立即登录/注册

微信扫码登录

0.0860s