python进阶之垃圾回收

内存使用

程序在运行的过程需要开辟内存空间,比如创建一个对象需要一片内存空间,定义变量需要内存空间。有内存的开辟,势必也要有内存的释放,不然只进不出那不是貔貅了吗?即使有开辟有释放在短期内还是会有垃圾内存的存在。

内存管理

在有些语言中,内存的开辟和回收需要在代码中完成,典型的例子就是C语言。C语言中开辟一块内存:ptr=(int*)malloc(sizeof(int)*n); 释放一块内存:free(ptr);这个过程是需要写在内存使用之前的程序中的(没有轮子怎么办,咱们自己造)。而Java,Python这类语言内存的开辟和回收不需要代码实现,在后台中有专门负责内存回收的机制GC。

python中使用的垃圾回收机制有两个:

1.引用计数,标记清除

2.隔代回收

引用计数,标记清除

python里每一个东西都是对象,它们的核心就是一个结构体:PyObject

typedef struct_object {
    int ob_refcnt;
    struct_typeobject *ob_type;
} PyObject;

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

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

创建对象时Python立即向操作系统请求内存,同时Python将对象的C结构体里的 ob_refcnt 的值设为1。

如果对变量a重新赋值,此时变量a就会指向一个新的对象,新对象的引用数值为1,旧对象引用计数的值就会被置成0。

当python 的垃圾回收机制发现内存中的对象的计数引用值为0时,它就发现该自己闪亮登场了。垃圾回收机制会销毁该对象,释放内存。

引用计数,标记清除这一招是十分奏效的,可以解决大部分的对象回收。但是就是有那么一些情况是这一招解决不了的,那就是循环引用所谓循环应用指的是两个对象互相引用,且成为了一个孤岛,没有别的对象关联。

这种情况下,引用计数值一直都是1,想要释放 ’tommorr‘ 不行,因为它被 ’another‘引用了,所以要先释放 ’another‘才能使用 ’tommor‘,但是’another‘又被tommorr引用,也无法释放。这该怎么办呢?这时需要python垃圾回收的第二个机制 隔代回收出马了。

隔代回收

隔代回收机制主要3板斧:

第一:所有创建的对象都会加入到零代链表中,并扫描零代链表中所有的循环引用。如图发现两个对象的循环引用。

  

第二:将发现的循环引用的引用计数都减1。

当循环引用计数值为0之后,就被标记清除,垃圾回收第一规则就生效。如果清除一次引用计数还不为0咋办呢?那就是第三步

 第三步:将零代中引用计数不为0的对象加入到一代链表中,在一代链表中会重复零代中的循环计数减1操作。同时如果生命力顽强到一代链表都没处理的,那么会加入到二代链表。

 

以上讲到的是垃圾回收机制的大体思路,其实python的垃圾回收机制比以上描述的要复杂很多,很多深奥的东西可以看篇文章:https://www.cnblogs.com/pinganzi/p/6646742.html

原文地址:https://www.cnblogs.com/goldsunshine/p/11561612.html