python里面的垃圾回收机制

文章链接:https://www.jianshu.com/p/1e375fb40506

 

Garbage collection(GC)

现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患。
对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自然不会让用户去处理如何分配回收内存的问题。
python里也同java一样采用了垃圾收集机制,不过不一样的是:
python采用的是引用计数机制为主标记-清除分代收集两种机制为辅的策略

 

GC系统所承担的工作远比“垃圾回收”多得多。它们负责三个重要任务:

  • 为新生成的对象分配内存
  • 识别那些垃圾对象
  • 从垃圾对象回收内存

  如果将应用程序比作人的身体:所有你所写的那些优雅的代码,业务逻辑,算法,应该就是大脑。垃圾回收就是应用程序那颗跃动的心。像心脏为身体其他器官提供血液和营养物那样,垃圾回收器为你的应该程序提供内存和对象。如果垃圾回收器停止工作或运行迟缓,像动脉阻塞,你的应用程序效率也会下降,直至最终死掉。

 

gc模块的自动垃圾回收机制

必须要import gc模块,并且is_enable()=True才会启动自动垃圾回收。
这个机制的主要作用就是发现并处理不可达的垃圾对象。

垃圾回收=垃圾检查+垃圾回收

1、引用计数机制:

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))
 
import sys

class A(object):
     def __init__(self):
         """初始化对象"""
         print ('object born id:%s'%str(hex(id(self))))

def f1():
 """循环引用变量与删除变量"""
 while True:
     c1=A()
     del c1

def func(c):
 """getrefcount() 返回对象的引用计数"""
 print ('object refcount is:',sys.getrefcount(c))

if __name__=='__main__':
     # 生成对象
     a=A()
     func(a)

    # 增强引用
     b=a
     func(a)

     # 销毁引用
     del b
     func(a)



结果:
object born id:0x1043059b0
object refcount is: 4
object refcount is: 5
object refcount is: 4

 

 

 


 


gc方式1:引用计数

若此对象无其他对象引用,则立马回收掉

优点:简单、实时(将处理垃圾时间分摊到运行代码时,而不是等到一次回收)

缺点:

1.保存对象引用数会占用一点点内存空间

2.每次执行语句都可能更新引用数,不再使用大的数据结构时,会引起大量对象被回收

3.不能处理循环引用的情况

 

gc方式2:标记-清除(Mark—Sweep)

此方式主要用来处理循环引用的情况,只有容器对象(list、dict、tuple,instance)才会出现循环引用的情况

 

 

处理过程

1.将所有容器对象放到一个双向链表中(链表为了方便插入删除),这些对象为0代

2.循环遍历链表,如果被本链表内的对象引入,自身的被引用数-1,如果被引用数为0,则触发引用计数回收条件,被回收掉

3.未被回收的对象,升级为1代

『标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢?

对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

 

何时触发

1.被引用为0时,立即回收当前对象

2.达到了垃圾回收的阈值,触发标记-清除

3.手动调用gc.collect()

4.Python虚拟机退出的时候

 
 




posted @ 2020-05-12 21:53  何双新  阅读(249)  评论(0编辑  收藏  举报