2.2垃圾回收:
主要作用:从经历过“引用计数器机制”仍未被释放的对象中,找到“循环引用”,干掉相关对象。
底层机制(了解&难):
怎样找到“循环引用”?:
(1)收集所有的“容器对象”,通过一个双链表进行引用。
容器对象:可以引用其他对象的对象。->列表、元组、字典、自定义类对象、。。。
非容器对象:
(2)针对每一个“容器对象”,通过一个变量gc_refs来记录当前对应的引用计数。
(3)对于每个“容器对象”,找到它引用的“容器对象”,并将这个“容器对象”引用计数-1
(4)经过步骤3之后,如果一个“容器对象”的引用计数为0,就代表这玩意可以被回收了。肯定是“循环引用”导致它活到现在。
如何提升查找“循环应用”的性能?
如果程序当中创建了多个对象,而针对每一个对象都要参与“检测”过程;则会非常的耗费性能。所以,基于这个问题,产生了一个假设:越命大的对象,越长寿。假设一个对象10次检测都没有被干掉,那认定,这个对象一定很长寿。就减少这货的“检测频率”。基于这种假设,设计了一套机制:
分代回收机制:
(1)默认一个对象被创建出来后,属于0代。
(2)如果经历过这一代“垃圾回收”后,依然存活。则划分到下一代。
(3)“垃圾回收”的周期顺序为:0代“垃圾回收”一定次数,会触发0代和1代回收。1代“垃圾回收”一定次数,会触发0代,1代和2代回收。
查看和设置相关参数:import gc、print(gc.get_threshold())、gc.set_threshold(700, 10, 5)
import gc print(gc.get_threshold()) gc.set_threshold(700, 10, 5) print(gc.get_threshold())
垃圾回收器当中,新增的对象个数-消亡的对象个数,达到一定阈值,才会触发,垃圾检测。
垃圾回收时机(掌握&简单):
自动回收:
触发条件:开启垃圾回收机制:gc.enable()->开启垃圾回收机制(默认开启)
gc.disable()->关闭垃圾回收机制
gc.isenable()->判定是否开启
并且
达到了垃圾回收的阈值:垃圾回收器中,新增的对象个数和释放的对象个数之差达到某个阈值的时候。
涉及方法:gc.get_threshold()->获取自动回收阈值
gc.set_threshold()->设置自动回收阈值
手动回收:
# 手动触发垃圾回收机制 import objgraph import gc class Person: pass class Dog: pass p = Person() d = Dog() p.pet = d d.master = p del p del d # 手动触发开关 gc.collect() print(objgraph.count("Person")) print(objgraph.count("Dog"))
2.3特殊场景:
循环应用-细节问题(不同版本兼容方案)
强引用:能触发引用计数器+1的引用都是强引用。
弱引用:能够引用真实对象,但不能使引用对象计数器+1,为弱引用。
3.测量对象的引用个数