Python自动管理内存,使开发者从手动分配和处理位置中解放出来.
它通过两种互补机制来做到这一点:参考计数和一个代相传的垃圾收集器,用于循环参考.
这篇文章涵盖了垃圾收集在CPython的操作方式.
在PyPy等其它执行中,它在不同的机制下工作Reference Countering: Python中每个对象都带有一个引用计数,这个计数法是多少引用指向它的.
此计数递增值当: 指定了新的引用 () 它存储在一个容器中( 列表, dict等) 对象传递到函数 当: 引用超出范围时会减少。
当计数击中零时,CPython会立即对对象进行定点.
这与Java,JS等垃圾收集语言或PyPy执行有关键区别,收集时间无法预测.
问题: 参考循环 仅靠参考计算无法处理循环引用, 对象相互参考, 并且即使无法从程序中获取, 其计数也保持在零以上 : 这导致记忆漏出.
解决方案:世代垃圾收集器 为了捕捉上述情景,Python包含一个单独的循环垃圾收集器,在模块中实施.
它基于代相传的假设:大多数物体会年轻地死去,所以最近创造的物体比长生物体更经常被检查.
物体分为三代: 世代描述收集频率 0 新创建的物体 最频繁的1个幸存的1个 对象起始于生成
0.
若能活过"收藏传",则被提升为"第1代",而后最终被提升为"第2代".
每一代都有一个阈值的分配数,触发了收藏传出: 这意味着第0代在700个净分配之后收集;第1代和第2代在前一代的10个收集之后收集。
循环检测方法 循环收集器只跟踪容器对象:列表,dicts,tuples,类例,关闭-任何能够持有另一个对象的引用.
每个被跟踪的物体都带有将它连接到每代列表的支架.
当一代人的分配-减去交易地点的计数超过其门槛值时,一个收款证就与该一代人相反: 将每个跟踪对象的重计复制到刮痕字段.
取出来自其他有轨电车物体的参考文献,此取出"内部"周期参考文献.
任何留有正数的,都必须从有轨电车系外参考,故保留.
从这些物体向外追踪 以拯救任何能够从它们得到的东西, 即使它在一个循环中。
仍然处于零位的东西是无法到达的,被扫走.
在传球后幸存的物体移动到下一代,并较少被检查.
整个操作的时间复杂性为O(n).
我们该和自行车收藏家打交道吗?
通常不会 不过...
有时可以使循环收集器失去功能,在能对性能敏感的代码中完成,避免创建参考周期.
实际影响观察 分配重回循环 生成- 0 收集触发在净分配阈值(默认700)后,所以反复创建并丢弃容器的代码可以触发频繁的通过: 第二个版本创造了一个dict而不是一百万,因此它跨越gen-0阈值的频率要低得多.
与父母/孩子结构打破可能的循环是一个典型的例子:一个有.父母和.孩子列表的节点每次增加一个孩子时都会创建一个循环:完全无助于根的再计算.
所以,当运行时,根的再计数 实际点击0, 同样的孩子在。
没有任何循环存在,因此自行车采集者不必在后期捕捉.