gc --- 垃圾回收器接口 弱引用 允许指向对象但不增加其引用计数 永生代 永久世代
gc.freeze()
冻结由垃圾回收器追踪的所有对象;将它们移至永久世代并在所有未来的回收操作中忽略它们。
如果一个进程将执行 fork()
而不执行 exec()
,则在子进程中避免不必要的写入时拷贝将最大化内存共享并减少总体内存使用。 这需要同时在父进程的内存页中避免创建已释放的“空洞”并确保在子进程中的 GC 回收不会触及源自父进程的长寿对象的 gc_refs
计数器。 要同时达成这两个目标,请在父进程中尽早调用 gc.disable()
,在 fork()
之前调用 gc.freeze()
,并在子进程中尽早调用 gc.enable()
。
Added in version 3.7.
python
gc.freeze()
Freeze all the objects tracked by the garbage collector; move them to a permanent generation and ignore them in all the future collections.
If a process will fork()
without exec()
, avoiding unnecessary copy-on-write in child processes will maximize memory sharing and reduce overall memory usage. This requires both avoiding creation of freed “holes” in memory pages in the parent process and ensuring that GC collections in child processes won’t touch the gc_refs
counter of long-lived objects originating in the parent process. To accomplish both, call gc.disable()
early in the parent process, gc.freeze()
right before fork()
, and gc.enable()
early in child processes.
Added in version 3.7.
实践:
1、
小结:
1、
weakref
模块提供的工具可以不必创建引用就能跟踪对象类定义了 __del__ 方法,但是删除对象时没有调用它。
这有几个可能的原因。
The del
statement does not necessarily call __del__()
-- it simply decrements the object's reference count, and if this reaches zero __del__()
is called.
If your data structures contain circular links (e.g. a tree where each child has a parent reference and each parent has a list of children) the reference counts will never go back to zero. Once in a while Python runs an algorithm to detect such cycles, but the garbage collector might run some time after the last reference to your data structure vanishes, so your __del__()
method may be called at an inconvenient and random time. This is inconvenient if you're trying to reproduce a problem. Worse, the order in which object's __del__()
methods are executed is arbitrary. You can run gc.collect()
to force a collection, but there are pathological cases where objects will never be collected.
Despite the cycle collector, it's still a good idea to define an explicit close()
method on objects to be called whenever you're done with them. The close()
method can then remove attributes that refer to subobjects. Don't call __del__()
directly -- __del__()
should call close()
and close()
should make sure that it can be called more than once for the same object.
另一种避免循环引用的做法是利用 weakref
模块,该模块允许指向对象但不增加其引用计数。例如,树状数据结构应该对父节点和同级节点使用弱引用(如果真要用的话!)
Finally, if your __del__()
method raises an exception, a warning message is printed to sys.stderr
.
11.6. 弱引用
Python 会自动进行内存管理(对大多数对象进行引用计数并使用 garbage collection 来清除循环引用)。 当某个对象的最后一个引用被移除后不久就会释放其所占用的内存。
此方式对大多数应用来说都适用,但偶尔也必须在对象持续被其他对象所使用时跟踪它们。 不幸的是,跟踪它们将创建一个会令其永久化的引用。 weakref
模块提供的工具可以不必创建引用就能跟踪对象。 当对象不再需要时,它将自动从一个弱引用表中被移除,并为弱引用对象触发一个回调。 典型应用包括对创建开销较大的对象进行缓存:
>>> import weakref, gc
>>> class A:
... def __init__(self, value):
... self.value = value
... def __repr__(self):
... return str(self.value)
...
>>> a = A(10) # create a reference
>>> d = weakref.WeakValueDictionary()
>>> d['primary'] = a # does not create a reference
>>> d['primary'] # fetch the object if it is still alive
10
>>> del a # remove the one reference
>>> gc.collect() # run garbage collection right away
0
>>> d['primary'] # entry was automatically removed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
d['primary'] # entry was automatically removed
File "C:/python311/lib/weakref.py", line 46, in __getitem__
o = self.data[key]()
KeyError: 'primary'
gc
— Garbage Collector interface
由于 Python 使用了带有引用计数的回收器,如果你确定你的程序不会产生循环引用,你可以关闭回收器。可以通过调用 gc.disable()
关闭自动垃圾回收。若要调试一个存在内存泄漏的程序,调用 gc.set_debug(gc.DEBUG_LEAK)
;
gc.collect(generation=2)
若被调用时不包含参数,则启动完全的垃圾回收。可选的参数 generation 可以是一个整数,指明需要回收哪一代(从 0 到 2 )的垃圾。当参数 generation 无效时,会引发 ValueError
异常。返回发现的不可达对象的数目。
垃圾回收器把所有对象分类为三代,其依据是对象在多少次垃圾回收后幸存。 新建对象会被放在最年轻代(第 0
代)。 如果一个对象在一次垃圾回收后幸存,它会被移入下一个较老代。 由于第 2
代是最老代,这一代的对象在一次垃圾回收后仍会保留原样。 为了确定何时要运行,垃圾回收器会跟踪自上一次回收后对象分配和释放的数量。 当分配数量减去释放数量的结果值大于 threshold0 时,垃圾回收就会开始。 初始时只有第 0
代会被检查。 如果自第 1
代被检查后第 0
代已被检查超过 threshold1 次,则第 1
也会被检查。 对于第三代来说情况还会更复杂,请参阅 Collecting the oldest generation 来了解详情。
gc.set_threshold(threshold0[, threshold1[, threshold2]])
设置垃圾回收阈值(收集频率)。 将 threshold0 设为零会禁用回收。
垃圾回收器把所有对象分类为三代,其依据是对象在多少次垃圾回收后幸存。 新建对象会被放在最年轻代(第 0
代)。 如果一个对象在一次垃圾回收后幸存,它会被移入下一个较老代。 由于第 2
代是最老代,这一代的对象在一次垃圾回收后仍会保留原样。 为了确定何时要运行,垃圾回收器会跟踪自上一次回收后对象分配和释放的数量。 当分配数量减去释放数量的结果值大于 threshold0 时,垃圾回收就会开始。 初始时只有第 0
代会被检查。 如果自第 1
代被检查后第 0
代已被检查超过 threshold1 次,则第 1
也会被检查。 对于第三代来说情况还会更复杂,请参阅 Collecting the oldest generation 来了解详情。
每当运行完整收集或最高代 (2) 收集时,为多个内置类型所维护的空闲列表会被清空。 由于特定类型特别是 float
的实现,在某些空闲列表中并非所有项都会被释放。
gc --- 垃圾回收器接口 — Python 3.11.3 文档 https://docs.python.org/zh-cn/3/library/gc.html#module-gc
此模块提供可选的垃圾回收器的接口,提供的功能包括:关闭收集器、调整收集频率、设置调试选项。它同时提供对回收器找到但是无法释放的不可达对象的访问。由于 Python 使用了带有引用计数的回收器,如果你确定你的程序不会产生循环引用,你可以关闭回收器。可以通过调用 gc.disable()
关闭自动垃圾回收。若要调试一个存在内存泄漏的程序,调用 gc.set_debug(gc.DEBUG_LEAK)
;需要注意的是,它包含 gc.DEBUG_SAVEALL
,使得被垃圾回收的对象会被存放在 gc.garbage 中以待检查。
gc
模块提供下列函数:
- gc.enable()
-
启用自动垃圾回收
- gc.disable()
-
停用自动垃圾回收
- gc.isenabled()
-
如果启用了自动回收则返回
True
。
- gc.collect(generation=2)
-
若被调用时不包含参数,则启动完全的垃圾回收。可选的参数 generation 可以是一个整数,指明需要回收哪一代(从 0 到 2 )的垃圾。当参数 generation 无效时,会引发
ValueError
异常。返回发现的不可达对象的数目。每当运行完整收集或最高代 (2) 收集时,为多个内置类型所维护的空闲列表会被清空。 由于特定类型特别是
float
的实现,在某些空闲列表中并非所有项都会被释放。
- gc.set_debug(flags)
-
设置垃圾回收器的调试标识位。调试信息会被写入
sys.stderr
。此文档末尾列出了各个标志位及其含义;可以使用位操作对多个标志位进行设置以控制调试器。
- gc.get_debug()
-
返回当前调试标识位。
- gc.get_objects(generation=None)
-
返回一个收集器所跟踪的所有对象的列表,所返回的列表除外。 如果 generation 不为 None,则只返回收集器所跟踪的属于该生成的对象。
在 3.8 版更改: 新的 generation 形参。
引发一个 审计事件
gc.get_objects
,附带参数generation
。
- gc.get_stats()
-
返回一个包含三个字典对象的列表,每个字典分别包含对应代的从解释器开始运行的垃圾回收统计数据。字典的键的数目在将来可能发生改变,目前每个字典包含以下内容:
-
collections
是该代被回收的次数; -
collected
是该代中被回收的对象总数; -
uncollectable
是在这一代中被发现无法收集的对象总数 (因此被移动到garbage
列表中)。
3.4 新版功能.
-
- gc.set_threshold(threshold0[, threshold1[, threshold2]])
-
设置垃圾回收阈值(收集频率)。 将 threshold0 设为零会禁用回收。
垃圾回收器把所有对象分类为三代,其依据是对象在多少次垃圾回收后幸存。 新建对象会被放在最年轻代(第
0
代)。 如果一个对象在一次垃圾回收后幸存,它会被移入下一个较老代。 由于第2
代是最老代,这一代的对象在一次垃圾回收后仍会保留原样。 为了确定何时要运行,垃圾回收器会跟踪自上一次回收后对象分配和释放的数量。 当分配数量减去释放数量的结果值大于 threshold0 时,垃圾回收就会开始。 初始时只有第0
代会被检查。 如果自第1
代被检查后第0
代已被检查超过 threshold1 次,则第1
也会被检查。 对于第三代来说情况还会更复杂,请参阅 Collecting the oldest generation 来了解详情。
- gc.get_count()
-
将当前回收计数以形为
(count0, count1, count2)
的元组返回。
- gc.get_threshold()
-
将当前回收阈值以形为
(threshold0, threshold1, threshold2)
的元组返回。
- gc.get_referrers(*objs)
-
返回直接引用任意一个 objs 的对象列表。这个函数只定位支持垃圾回收的容器;引用了其它对象但不支持垃圾回收的扩展类型不会被找到。
需要注意的是,已经解除对 objs 引用的对象,但仍存在于循环引用中未被回收时,仍然会被作为引用者出现在返回的列表当中。若要获取当前正在引用 objs 的对象,需要调用
collect()
然后再调用get_referrers()
。警告
在使用
get_referrers()
返回的对象时必须要小心,因为其中一些对象可能仍在构造中因此处于暂时的无效状态。不要把get_referrers()
用于调试以外的其它目的。引发一个 审计事件
gc.get_referrers
,附带参数objs
。
- gc.get_referents(*objs)
-
返回被任意一个参数中的对象直接引用的对象的列表。返回的被引用对象是被参数中的对象的C语言级别方法(若存在)
tp_traverse
访问到的对象,可能不是所有的实际直接可达对象。只有支持垃圾回收的对象支持tp_traverse
方法,并且此方法只会在需要访问涉及循环引用的对象时使用。因此,可以有以下例子:一个整数对其中一个参数是直接可达的,这个整数有可能出现或不出现在返回的结果列表当中。引发一个 审计事件
gc.get_referents
,附带参数objs
。
- gc.is_tracked(obj)
-
当对象正在被垃圾回收器监控时返回
True
,否则返回False
。一般来说,原子类的实例不会被监控,而非原子类(如容器、用户自定义的对象)会被监控。然而,会有一些特定类型的优化以便减少垃圾回收器在简单实例(如只含有原子性的键和值的字典)上的消耗。>>> gc.is_tracked(0) False >>> gc.is_tracked("a") False >>> gc.is_tracked([]) True >>> gc.is_tracked({}) False >>> gc.is_tracked({"a": 1}) False >>> gc.is_tracked({"a": []}) True
3.1 新版功能.
- gc.is_finalized(obj)
-
如果给定对象已被垃圾回收器终结则返回
True
,否则返回False
。>>> x = None >>> class Lazarus: ... def __del__(self): ... global x ... x = self ... >>> lazarus = Lazarus() >>> gc.is_finalized(lazarus) False >>> del lazarus >>> gc.is_finalized(x) True
3.9 新版功能.
- gc.freeze()
-
Freeze all the objects tracked by the garbage collector; move them to a permanent generation and ignore them in all the future collections.
If a process will
fork()
withoutexec()
, avoiding unnecessary copy-on-write in child processes will maximize memory sharing and reduce overall memory usage. This requires both avoiding creation of freed "holes" in memory pages in the parent process and ensuring that GC collections in child processes won't touch thegc_refs
counter of long-lived objects originating in the parent process. To accomplish both, callgc.disable()
early in the parent process,gc.freeze()
right beforefork()
, andgc.enable()
early in child processes.3.7 新版功能.
- gc.unfreeze()
-
解冻永久代中的对象,并将它们放回到年老代中。
3.7 新版功能.
- gc.get_freeze_count()
-
返回永久代中的对象数量。
3.7 新版功能.
提供以下变量仅供只读访问(你可以修改但不应该重绑定它们):
- gc.garbage
-
一个回收器发现不可达而又无法被释放的对象(不可回收对象)列表。 从 Python 3.4 开始,该列表在大多数时候都应该是空的,除非使用了含有非
NULL
tp_del
空位的 C 扩展类型的实例。如果设置了
DEBUG_SAVEALL
,则所有不可访问对象将被添加至该列表而不会被释放。在 3.2 版更改: 当 interpreter shutdown 即解释器关闭时,若此列表非空,会产生
ResourceWarning
,即资源警告,在默认情况下此警告不会被提醒。如果设置了DEBUG_UNCOLLECTABLE
,所有无法被回收的对象会被打印。在 3.4 版更改: 根据 PEP 442 ,带有
__del__()
方法的对象最终不再会进入gc.garbage
。
- gc.callbacks
-
在垃圾回收器开始前和完成后会被调用的一系列回调函数。这些回调函数在被调用时使用两个参数: phase 和 info 。
phase 可为以下两值之一:
"start": 垃圾回收即将开始。
"stop": 垃圾回收已结束。
info is a dict providing more information for the callback. The following keys are currently defined:
"generation"(代) :正在被回收的最久远的一代。
"collected"(已回收的 ): 当*phase* 为 "stop" 时,被成功回收的对象的数目。
"uncollectable"(不可回收的): 当 phase 为 "stop" 时,不能被回收并被放入
garbage
的对象的数目。应用程序可以把他们自己的回调函数加入此列表。主要的使用场景有:
统计垃圾回收的数据,如:不同代的回收频率、回收所花费的时间。
使应用程序可以识别和清理他们自己的在
garbage
中的不可回收类型的对象。3.3 新版功能.
以下常量被用于 set_debug()
:
- gc.DEBUG_STATS
-
在回收完成后打印统计信息。当回收频率设置较高时,这些信息会比较有用。
- gc.DEBUG_COLLECTABLE
-
当发现可回收对象时打印信息。
- gc.DEBUG_UNCOLLECTABLE
-
打印找到的不可回收对象的信息(指不能被回收器回收的不可达对象)。这些对象会被添加到
garbage
列表中。在 3.2 版更改: 当 interpreter shutdown 时,即解释器关闭时,若
garbage
列表中存在对象,这些对象也会被打印输出。
- gc.DEBUG_SAVEALL
-
设置后,所有回收器找到的不可达对象会被添加进 garbage 而不是直接被释放。这在调试一个内存泄漏的程序时会很有用。
- gc.DEBUG_LEAK
-
调试内存泄漏的程序时,使回收器打印信息的调试标识位。(等价于
DEBUG_COLLECTABLE | DEBUG_UNCOLLECTABLE | DEBUG_SAVEALL
)。