来源:python中国网 时间:2019-07-13

  gc模块提供一个接口给开发者设置垃圾回收的选项。

  一、有三种情况会触发垃圾回收:

  1、调用gc.collect(),

  2、当gc模块的计数器达到阀值的时候。

  3、程序退出的时候

  常用函数:

  1、gc.set_debug(flags)设置gc的debug日志,一般设置为gc.DEBUG_LEAK

  2、gc.collect([generation])显式进行垃圾回收,可以输入参数,0代表只检查第一代的对象,1代表检查一,二代的对象,2代表检查一,二,三代的对象,如果不传参数,执行一个fullcollection,也就是等于传2,返回值为不可达(unreachableobjects)对象的数目(即一共释放掉的对象个数)。

  3、gc.get_threshold()获取的gc模块中自动执行垃圾回收的频率。这个方法返回的是(700,10,10),这也是gc的默认值。意思是在第0代对象数量达到700个之前,不把未被回收的对象放入第一代,在第一代对象数量达到10个之前也不把未被回收的对象移到第二代。

  4、gc.set_threshold(threshold0[,threshold1[,threshold2])手动设置阈值。

  5、gc.get_count()获取当前自动执行垃圾回收的计数器,返回一个长度为3的列表

  说明:

  垃圾回收后的对象会放在gc.garbage列表里面

  gc.collect()会返回不可达的对象数目,4等于两个对象以及它们对应的dict

# -*- coding: utf-8 -*-
import gc

class ClassA():
    def __init__(self):
        print('object born,id:%s'%str(hex(id(self))))
    # def __del__(self):
    #     print('object del,id:%s'%str(hex(id(self))))

def f3():
    print("-----0------")
    # print(gc.collect())
    c1 = ClassA()
    c2 = ClassA()
    c1.t = c2
    c2.t = c1
    print("-----1------")
    del c1
    del c2
    print("-----2------")
    print(gc.garbage)
    print("-----3------")
    print(gc.collect()) #显式执行垃圾回收
    print("-----4------")
    print(gc.garbage)
    print("-----5------")

if __name__ == '__main__':
    gc.set_debug(gc.DEBUG_LEAK) #设置gc模块的日志
    f3()


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

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

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

  在Python中,采用分代收集的方法。把对象分为三代,一开始,对象在创建的时候,放在一代中,如果在一次一代的垃圾检查中,改对象存活下来,就会被放到二代中,同理在一次二代的垃圾检查中,该对象存活下来,就会被放到三代中。

  gc模块里面会有一个长度为3的列表的计数器,可以通过gc.get_count()获取。

  例如(488,3,0),其中488是指距离上一次一代垃圾检查,Python分配内存的数目减去释放内存的数目,注意是内存分配,而不是引用计数的增加。例如:

print gc.get_count() # (590, 8, 0)
a = ClassA()
print gc.get_count() # (591, 8, 0)
del a
print gc.get_count() # (590, 8, 0)


  3是指距离上一次二代垃圾检查,一代垃圾检查的次数,同理,0是指距离上一次三代垃圾检查,二代垃圾检查的次数。

  gc模快有一个自动垃圾回收的阀值,即通过gc.get_threshold函数获取到的长度为3的元组,例如(700,10,10)每一次计数器的增加,gc模块就会检查增加后的计数是否达到阀值的数目,如果是,就会执行对应的代数的垃圾检查,然后重置计数器

  例如,假设阀值是(700,10,10):

当计数器从(699,3,0)增加到(700,3,0),gc模块就会执行gc.collect(0),即检查一代对象的垃圾,并重置计数器为(0,4,0)
当计数器从(699,9,0)增加到(700,9,0),gc模块就会执行gc.collect(1),即检查一、二代对象的垃圾,并重置计数器为(0,0,1)
当计数器从(699,9,9)增加到(700,9,9),gc模块就会执行gc.collect(2),即检查一、二、三代对象的垃圾,并重置计数器为(0,0,0)

  当计数器从(699,3,0)增加到(700,3,0),gc模块就会执行gc.collect(0),即检查一代对象的垃圾,并重置计数器为(0,4,0)

  当计数器从(699,9,0)增加到(700,9,0),gc模块就会执行gc.collect(1),即检查一、二代对象的垃圾,并重置计数器为(0,0,1)

  当计数器从(699,9,9)增加到(700,9,9),gc模块就会执行gc.collect(2),即检查一、二、三代对象的垃圾,并重置计数器为(0,0,0)

  注意点

  gc模块唯一处理不了的是循环引用的类都有__del__方法,所以项目中要避免定义__del__方法。如果一定要使用该方法,同时导致了循环引用,需要代码显式调用gc.garbage里面的对象的__del__来改变局面。