python的垃圾回收,怎么实现的-,python可以自动回收垃圾吗

  python的垃圾回收,怎么实现的?,python可以自动回收垃圾吗

  

  一、写在前面:

  我们都知道Python是一种面向对象的脚本语言,对象是Python中一个非常重要的概念。在Python中,数字是对象,字符串是对象,一切都是对象,它们的核心是一个结构体——py object。

  typedefstruct_object{

  intob _ refcnt

  struct _ typeobject * ob _ type

  } PyObjectPyObject是每个对象的必要内容,其中ob_refcnt用作引用计数。

  二、垃圾回收机制

  大家应该或多或少听说过垃圾回收,但是什么是垃圾回收呢?我们说的垃圾收集,绝对不是指把垃圾扔进垃圾桶。现在的Java、C#等高级语言都采用了垃圾回收机制,而不是C、C中用户自己管理维护内存的方式,自己管理内存非常自由,但是可能会出现内存泄漏、悬空指针等问题。作为现代编程语言的自动内存管理机制,垃圾收集机制主要关注两点:1 .在内存中寻找无用的垃圾资源;2.清除垃圾并为其他对象释放内存。

  相关:《Python视频教程》

  三、Python中的垃圾回收

  在Python中,垃圾收集机制主要是以引用计数为主要手段,以标签清除和分代收集机制为辅助手段来实现的。

  1.引用计数

  通过前面的介绍,我们已经知道PyObject是每个对象的必备内容,当一个对象有了新的引用,它的ob_refcnt就会增加;当引用对象被删除时,它的ob_refcnt会减少;当引用计数为0时,对象的寿命将结束。

  让我们看看在引用计数为1的情况下会发生什么:

  (1)创建对象:

  实际上,对象123并不是在内存中新创建的,因为Python启动解释器时会创建一个小的整数池,-5到256之间的整数对象会自动加载到内存中进行调用。因此,a=123是对整数对象123的附加引用。和456不在整数池中,需要创建一个对象。最后一个参考数字2呢?因为sys.getrefcount(b)也是一个引用。

  (2)对象被引用:

  每次赋值操作都会增加数据引用的数量。记住,引用的变量A、B和C指向数据456,而不是变量本身。

  (3)将对象作为参数传递给函数:

  这里可以清楚地看到,引用计数在被传入函数后增加了1。

  (4)对象作为元素存储在容器中:

  这里,创建对象后,我们分别向列表和元组添加一个,引用计数增加。

  虽然每次释放内存都必须管理引用计数,但是与其他垃圾收集技术相比,引用计数具有“实时”的优势。如果这个对象没有引用,就直接释放内存,而其他垃圾回收技术只能在某些特殊情况下回收无效内存。但是引用计数带来的维护引用计数的额外操作与Python中的内存分配和释放,以及引用赋值的次数成正比。除此之外,引用计数机制还有一个弱点——不能解决循环引用带来的问题。循环引用会使引用对象的引用计数不为零。但是这些对象实际上没有被任何外部对象引用,只是相互引用,也就是说这组对象占用的内存空间要回收。但是由于循环引用导致的引用计数不为零,所以这组对象占用的内存空间永远不会被释放。如下,list1和list2相互引用。如果没有其他对象引用它们,list1和list2的引用计数仍然是1,占用的内存永远不会被回收,这是致命的。

  list1=[]

  list2=[]

  列表1 .追加(列表2)

  2.追加(列表1) 2。清除标记

  标记清扫算法是一种基于跟踪GC技术的垃圾收集算法。分为两个阶段:第一个阶段是标记阶段,在这个阶段GC会标记所有的活动对象,第二个阶段是回收那些未标记的对象和不活动的对象。

  对象通过引用(指针)连接起来,形成一个有向图。对象形成有向图的节点,引用关系形成有向图的边。从根对象开始,沿有向边遍历对象,可达对象标记为活动对象,不可达对象为待清除的非活动对象。对象是全局变量、调用栈和寄存器。

  在上图中,块1可以从程序变量中直接访问,块2和块3可以间接访问。该程序无法访问块4和块5。第一步将标记块1并记住块2和块3以备后用。

  理。第二步将标记块2,第三步将标记块3,但不记得块2,因为它已被标记。扫描阶段将忽略块1,2和3,因为它们已被标记,但会回收块4和5。

  标记清除算法作为Python的辅助垃圾收集技术,主要处理的是一些容器对象,比如list、dict、tuple等,因为对于字符串、数值对象是不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。不过,这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。

  3、分代回收

  分代回收是建立在标记清除技术基础之上的,是一种以空间换时间的操作方式。

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

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: