• <转> python的垃圾回收机制


    Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题。通过“分代回收”(generation collection)以空间换取时间来进一步提高垃圾回收的效率。

    引用计数机制:
        python里每一个东西都是对象,它们的核心就是一个结构体:PyObject
    1 typedef struct_object {
    2     int ob_refcnt;
    3     struct_typeobject *ob_type;
    4 }PyObject;

    PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。

    1  #define Py_INCREF(op)   ((op)->ob_refcnt++)          //增加计数
    2  #define Py_DECREF(op)                               //减少计数        
    3       if (--(op)->ob_refcnt != 0)    
    4           ;        
    5       else         
    6           __Py_Dealloc((PyObject *)(op))

     引用计数为0时,该对象生命就结束了。

        引用计数机制的优点:
             1、简单
            2、实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。        
        引用计数机制的缺点: 
            1、维护引用计数消耗资源 
            2、循环引用 
     
     list1 = []
     list2 = []
     list1.append(list2)
     list2.append(list1)
    list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。
        对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制。

    上面说到python里回收机制是以引用计数为主,标记-清除和分代收集两种机制为辅。

    1、标记-清除机制

    标记-清除机制,顾名思义,首先标记对象(垃圾检测),然后清除垃圾(垃圾回收)。如图:

    首先初始所有对象标记为白色,并确定根节点对象(这些对象是不会被删除),标记它们为黑色(表示对象有效)。将有效对象引用的对象标记为灰色(表示对象可达,但它们所引用的对象还没检查),检查完灰色对象引用的对象后,将灰色标记为黑色。重复直到不存在灰色节点为止。最后白色结点都是需要清除的对象。

    2、回收对象的组织

    这里所采用的高级机制作为引用计数的辅助机制,用于解决产生的循环引用问题。而循环引用只会出现在“内部存在可以对其他对象引用的对象”,比如:list,class等。

    为了要将这些回收对象组织起来,需要建立一个链表。自然,每个被收集的对象内就需要多提供一些信息,下面代码是回收对象里必然出现的。

    1  /* GC information is stored BEFORE the object structure. */
    2  typedef union _gc_head {
    3      struct {
    4          union _gc_head *gc_next;
    5          union _gc_head *gc_prev;
    6          Py_ssize_t gc_refs;
    7      } gc;
    8      long double dummy;  /* force worst-case alignment */
    9  } PyGC_Head;

    一个对象的实际结构如图所示:

    通过PyGC_Head的指针将每个回收对象连接起来,形成了一个链表,也就是在1里提到的初始化的所有对象。

     

    3、分代回收技术

    分代技术是一种典型的以空间换时间的技术,这也正是java里的关键技术。这种思想简单点说就是:对象存在时间越长,越可能不是垃圾,应该越少去收集。

    这样的思想,可以减少标记-清除机制所带来的额外操作。分代就是将回收对象分成数个代,每个代就是一个链表(集合),代进行标记-清除的时间与代内对象

    存活时间成正比例关系

     1   /*** Global GC state ***/
     2   
     3   struct gc_generation {
     4       PyGC_Head head;
     5       int threshold; /* collection threshold */
     6       int count; /* count of allocations or collections of younger
     7                     generations */
     8   };//每个代的结构
     9   
    10  #define NUM_GENERATIONS 3//代的个数
    11  #define GEN_HEAD(n) (&generations[n].head)
    12  
    13  /* linked lists of container objects */
    14  static struct gc_generation generations[NUM_GENERATIONS] = {
    15      /* PyGC_Head,                               threshold,      count */
    16      {{{GEN_HEAD(0), GEN_HEAD(0), 0}},           700,            0},
    17      {{{GEN_HEAD(1), GEN_HEAD(1), 0}},           10,             0},
    18      {{{GEN_HEAD(2), GEN_HEAD(2), 0}},           10,             0},
    19  };
    20  
    21  PyGC_Head *_PyGC_generation0 = GEN_HEAD(0);

      

    从上面代码可以看出python里一共有三代,每个代的threshold值表示该代最多容纳对象的个数。默认情况下,当0代超过700,或1,2代超过10,垃圾回收机制将触发。

    0代触发将清理所有三代,1代触发会清理1,2代,2代触发后只会清理自己。

    一个完整的垃圾回收流程包括以下四步:链表建立,确定根节点,垃圾标记,垃圾回收~  以下博客进行了很好的阐述:https://my.oschina.net/hebianxizao/blog/59896

    原文地址:http://www.cnblogs.com/hackerl/p/5901553.html

  • 相关阅读:
    Scrapy选择器和持久化
    SQLAlchemy
    Python数据库连接池DBUtils
    flask应用上下文和g
    flask请求上下文源码解析
    flask的session源码流程和第三方组件
    430软狗不喂狗后系统起不来的问题
    VS2008 快捷键大全
    未能加载或程序集“XXXX,Version=0.0.0.0,Culter=neutral,PublicKeyToken=null”或它的某一个依赖项。试图加载格式不正确的程序。
    用vs2008打开vs2005项目
  • 原文地址:https://www.cnblogs.com/webber1992/p/6597245.html
Copyright © 2020-2023  润新知