Python垃圾回收机制

Python 垃圾回收机制是“引用计数”为主,“标记-清除”和“分代回收”为辅。

 

1、引用计数(Reference Counting)

原理 :Python的核心思想是,一切皆对象(Object)。每个对象会维护一个引用计数(ob_refcnt),当一个对象被引用时,它的引用计数会 +1;相反,当对象被取消引用时,它的引用计数则会 -1。当引用计数为 0 时,对象的生命就结束了,系统会回收该对象,并释放相应的内存;
 
实例

import sys

print("Hello, World!")                              # 创建一个 "Hello, World!" 字符串对象并打印
print(id("Hello, World!"))                         # 打印 "Hello, World!" 的内存地址
print(sys.getrefcount("Hello, World!"))    # 打印 "Hello, World!" 的引用计数

a = "Hello, World!"                                   # 建立变量 a 对字符串对象的引用
print(id(a))                                               # 打印 a 的内存地址,是 "Hello, World!" 的内存地址
print(sys.getrefcount("Hello, World!"))    # 打印 "Hello, World!" 的引用计数, +1

b = a                                                        # 变量 b 通过 a 建立对 "Hello, World!" 对象的引用
print(id(b))                                               # 打印 a 的内存地址,是 "Hello, World!" 的内存地址
print(sys.getrefcount("Hello, World!"))    # 打印 "Hello, World!" 的引用计数, +1

del b
print(sys.getrefcount("Hello, World!"))    # 打印 "Hello, World!" 的引用计数, -1
del a
print(sys.getrefcount("Hello, World!"))    # 打印 "Hello, World!" 的引用计数, -1

执行结果:

Hello, World!        # 字符串对象的打印结果
4374614320       # 字符串对象的内存地址
3                           # 字符串对象的引用计数

4374614320       # 变量 a 的 id,其实是字符串的 id
4                           # 字符串的引用计数 +1

4374614320       # 变量 b 的 id,其实是字符串的 id
5                          # 字符串的引用计数 +1

4                          # 删除变量 b,字符串引用计数 -1
3                          # 删除变量 a,字符串引用计数 -1

 
引用计数 +1 的情况

  • 对象被创建。例如,a='Hello, World!'
  • 对象被引用。例如,a=b
  • 对象被作为元素,存储在容器中。例如,collection=[a, 'This is Allen.']
  • 对象被作为参数,传入到函数中。例如,func(a)

 
引用计数 -1 的情况

  • 变量名被删除。例如,del a
  • 变量名指向其它对象。例如,a=3
  • 对象所在的容器被删除,或从容器中删除对象。例如,collection.pop(0)
  • 对象离开所在的作用域。例如,函数执行完毕,func()函数中的局部变量;

 
优点 :简单、易于理解,有很高的实时性,一旦没有引用,内存就直接释放;

 
缺点 :维护引用计数需要消耗资源,无法解决循环引用的问题;

 

2、标记-清除(Mark and Sweep)

原理 :顾名思义,先标记(垃圾检测),再清除(垃圾回收)。对象之间通过引用连在一起,构成一个有向图,对象是有向图的节点,而引用关系构成这个有向图的边。从根对象(全局变量、调用栈、寄存器)出发,沿着有向边遍历对象,可达的对象标记为活动对象,不可达的对象就是要被清除的非活动对象。

在上图中,从黑点(根对象)出发,对象1、2、3可达,被标记为活动对象,对象4、5不可达,为非活动对象,会被回收。标记清除算法维护了一个双向链表数据结构,主要用于处理list、tuple、dict等一些容器对象的循环引用问题,字符串、数值对象不存在循环引用问题。
 
优点 :解决了循环引用问题;
 
缺点 :每次都要遍历全图,性能耗费较大;

 

3、分代回收(Generational Collection)

原理 :Python 将所有对象分为3代,每一代都维护一个链表。刚创建的对象是第0代;经过第一次垃圾回收后,依然存在的对象,会被移动到第1代,再经过一次垃圾回收,依然存在的会被移动到第2代。每一代都有自动垃圾回收的阀值(可以指定)。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。

分代回收是一种以空间换时间的操作方式,是建立在标记清除的基础之上,作为Python的辅助垃圾回收机制处理容器对象。

 

posted @ 2020-04-12 14:27  mazinga  阅读(188)  评论(0)    收藏  举报