概览:

      主要通过 引用计数来进行垃圾收集, 就是说,当一个对象没有被其他对象引用的时候,会释放掉内存。
    但是会有一些循环引用的对象,通过上面的方法,是没有办法清除掉的。所以,python还有另外的一个机制来解决这个问题,那就是标记-清除。

标记-清除:

        主要过程为, 扫描所有容器对象(不会扫描int, string,这些简单对象,因为他们不能包含其他对象的引用,不会造成循环引用),通过一种方法将这些对象分为两部分,一部分表示可以被删除,一部分表示不可被删除,然后将可以被删除的对象回收掉。
    那么首先一个问题,如何组织这些container对象呢?python采用了双向链表来跟踪这些对象,所有的container对象在创建之后,都会被插入到链表里。每个container对象里面都会有一个 PyGC_HEAD结构。
  1. typedef union _gc_head {
  2. struct {
  3. union _gc_head *gc_next;
  4. union _gc_head *gc_prev;
  5. Py_ssize_t gc_refs;
  6. } gc;
  7. double dummy; /* force worst-case alignment */
  8. } PyGC_Head;
这个结构中,很明显,gc_next 和 gc_prev 是实现双向链表的两个指针,  gc_refs在后面解决双向引用的时候会用到。
    通过上面的方法,每当有container对象被创建,就会将他加入到内部维护的可收集对象链表里。这样每次执行垃圾收集的时候,就可以遍历这些链表,进行标记清除啦。但是这样又存在一个问题,在执行垃圾收集的时候,程序是被暂停执行的,垃圾收集结束之后才会继续执行。 每次执行垃圾收集,都需要遍历所有的container对象,如果当前进程中对象比较多的话,会影响程序的执行效率。 一个优化的方法就是:分代收集

分代收集

       分代收集基于这样一个统计事实: 程序执行期间,有一部分内存块会在很短的时间分配,然后又被释放。而那些存活时间越久的内存块就越不容易被释放,甚至可能在程序执行期间一直存活,事实上这部分所占的比例还不小。所以,python将系统中存活的内存块根据其存活时间将其分为三个不同的代(年轻代, 青年代, 老年代)。每一个代对应上面描述的一个双向链表。新创建的container对象会被加入到年轻代中,如果他经历了几次回收之后依然存活,那么就把他放入青年代。依次类推。这样可以降低老年代和青年代的扫描频率。因为越老的内存块,扫描之后可以被释放的几率越小, 所以优先扫描年轻的代。
    每一个代(双向链表)所容纳的对象个数是有限的,当超过了这个限制,就会触发一次 标记-清除 的过程。目前的版本(python3.5.2, 年轻代是700, 青年代和老年代是10)
    那么,如何进行标记-清除的过程呢。比如我们要对青年代进行一次垃圾收集。我们需要从这个链表中的对象中 找到那些被可收集链表以外的对象引用的对象放入 root object集合。然后从这些root object开始遍历可收集链表,从中找出需要删除的对象(也就是存在循环引用的对象)放入unreachable集合里面。然后对unreachable集合中的对象执行回收。 如何找到哪些对象是循环引用的呢?假设对象A,和 B 的引用计数都为1,但是A引用了B,B同时引用了A,所以A和B是可以被回收的。我们需要识别出这种对象,把他放入unreachable集合里。所以我们首先需要解除摘除循环引用,我们首先遍历可收集链表,将其中每个对象的引用计数都减1,这样A和B的引用计数都变为了0。这样,剩下的对象中,如果他的引用计数仍然大于0,说明这个对象不可被删除(因为不止有一个对象在引用他),我们把它放入root object集合里。(ps:这里有个问题,假入对对象C的引用计数减1,这时候对象C的引用计数为0,但是其实C是有其他对象在引用的,那岂不是出问题了,这里就用到了上面PyGC_Head 里面的gc_refs, 也就是并不是直接操作对象C的引用计数,而是拷贝了一个副本,这个变量就是用来干这个的)。
    现在我们有了一个root object集合,这个集合里的对象是不能被删除的。所以,这些对象引用的对象也是不可被删除的。现在只需要遍历可收集链表,就可以找到unreacheble对象。完成标记之后,执行回收。
 
注意:

当python中自己实现了 __del__() 方法时,对于这样的对象,跟据 Python 的定义,在释放该对象占用的资源前需要调用该函数。由于 Python 的垃圾回收机制不能保证垃圾回收的顺序,可能在删除 b 之后,在 a.__del__() 中仍然会调用 b 对象,这样将会造成异常。

为此,Python 采取了比较保守的策略,也就是说对于当自定的类,如果存在 __del__() 时,不会对该对象进行垃圾回收。这样的对象,Python 会直接放到一个 garbage 列表中,这个列表在运行期间不会释放,对于 Python 来说不会有内存泄露,但是对于该程序来说,实际上已经发生了内存泄露

python垃圾回收机制的一些理解的更多相关文章

  1. 简述Python垃圾回收机制和常量池的验证

    目录 通过代码验证python解释器内部使用了常量池 Python的引入 变量的引入 为什么要有变量 定义变量 常量引入 常量池引入 Python解释器 Python变量存储机制 Python垃圾回收 ...

  2. python垃圾回收机制与小整数池

    python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...

  3. python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除

    js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...

  4. 浅析Python垃圾回收机制!

    Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...

  5. 从 CPython 源码角度看 Python 垃圾回收机制

    环状双向链表 refchain 在 Python 程序中创建的任何对象都会被放到 refchain 链表中,当创建一个 Python 对象时,内部实际上创建了一些基本的数据: 上一个对象 下一个对象 ...

  6. Python垃圾回收机制--完美讲解!

    转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...

  7. python垃圾回收机制(Garbage collection)

    由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...

  8. Python 构造函数、 Python 析构函数、Python 垃圾回收机制

    构造函数与析构函数 构造函数: 用于初始化类的内容部状态,Python提供的构造函数式 __init__(); 也就是当该类被实例化的时候就会执行该函数.那么我们就可以把要先初始化的属性放到这个函数里 ...

  9. 浅谈python垃圾回收机制

    引入 ​ 解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那 ...

随机推荐

  1. October 23rd Week 44th Sunday 2016

    When ambition ends, happiness begins. 野心消亡之日,正是快乐破茧之时. No ambition, no annoyance. No ambition, no ac ...

  2. bzoj4260

    题目大意:求不相交的两段区间,两段的异或和加起来最大是多少 区间异或和记得转化成前缀和啊我个sb 变成一对数的异或值就变成trie了啊 两段区间的话,从左往右一颗trie,从右往左一颗trie #in ...

  3. Git Push 避免用户名和密码方法

    参考这里: http://www.cnblogs.com/ballwql/p/3462104.html 亲测第一种方法有效

  4. 浏览器-08 chromium 渲染2

    Chromium 硬件加速合成 一个网页通常可以包

  5. 如何使用的Ue4自带的SQLiteSupport

    在UE4.6版本加入的模块.可以让开发者使用SQLite数据库.SQlite是个轻量型的本地数据库. 我下面就来介绍一下如何使用这个模块. 第一步:下载SQLite源代码以及SQLite GUI管理工 ...

  6. Pig语言基础-【持续更新中】

      ***本文参考了Pig官方文档以及已有的一些博客,并加上了自己的一些知识性的理解.目前正在持续更新中.***   Pig作为一种处理大规模数据的高级查询语言,底层是转换成MapReduce实现的, ...

  7. 咪咕视讯与美国AR公司ODG达成战略合作,联合打造尖端产品

    昨日,中国移动下属生态公司咪咕视讯科技有限公司(简称咪咕视讯)与美国AR公司Osterhout Design Group (ODG)达成战略合作.本次合作将充分发挥ODG的先进技术优势,与咪咕视讯共同 ...

  8. bzoj1468 Tree

    最经典的点分治题目,在递归子树的时候减去在算父亲时的不合法方案. #include<iostream> #include<cstdio> #include<cstring ...

  9. STM32之EXTI——外部中断

    互联网的广大网友,大家早上中午晚上好.EXTI...故名思义..EX表外,出..I表示Intrrupt..所以合起来就是外部中断...说到这..我觉得我最近的六级水平(背单词)又进了一步,稍微自夸了下 ...

  10. spark 2.0 Vector toBreeze

    def toBreeze( _v : Vector ) : BZV[Double] = { _v match { case x : org.apache.spark.mllib.linalg.Dens ...