Python垃圾回收机制
Python程序在运行的时候, 需要在内存中开辟一块空间, 用于存放运行时产生的临时变量, 计算完成后, 再将结果输出到永久性存储器中。如果数据量过大, 内存空间管理不善就很容易出现OOM(out of memory)的现象, 程序就会被系统中断。因此, 需要一种内存管理机制, Python垃圾回收机制就是一种自动内存管理机制, 在某些情况下, 开发者还需要手动进行垃圾回收。
内存泄漏
这里的泄漏, 并不是说内存出现了信息安全的问题, 被恶意程序利用了, 而是指程序没有设计好, 导致程序未能释放已经不再使用的内存。对于不再使用的内存空间, Python通过如下机制来回收。
引用计数(Reference Counting)
Python中一切皆为对象, 每个对象都有一个引用计数器, , 记录有多少引用指向该对象, 当这个对象的引用计数为0
的时候, 这个对象就成为了垃圾, Python会立即回收该对象的内存。
- 引用计数增加的情况:
- 对象被创建时(如
x = 10
) - 对象被赋值给其他变量时(如
y = x
) - 对象被作为参数传递给函数时引用计数会加2, 一次来自参数引用, 一次来自函数调用栈引用
- 对象被添加到容器中时(如
list.append(x)
)
- 对象被创建时(如
- 引用计数减少的情况:
- 变量被显式删除时(如
del x
) - 变量被赋值为None时
- 对象离开作用域时(如函数执行完毕)
- 对象从容器中被移除时(如
list.remove(obj)
) 需要注意
- 变量被显式删除时(如
- 在 Python 中, 当一个对象被创建并赋值给一个变量时, 它的引用计数会被初始化为
1
- 引用计数回收机制无法处理循环引用(即两个或多个对象互相引用, 但外部没有引用指向他们的情况) **
循环垃圾收集器(Cycle Collector)
为解决循环引用问题, Python引入了循环垃圾收集器, 它是gc
模块的一部分
- 工作原理
- 循环垃圾收集器会定期检查不可达对象(即无法通过引用链访问到的对象)
- 它通过标记-清除(Mark-and-Sweep)算法来检测和回收循环引用的对象
- 触发条件
- 当对象的引用计数不为
0
, 但无法通过任何引用链访问到时 - 当
gc
模块的阈值被触发时(如对象分配数量达到一定值)
- 当对象的引用计数不为
- 手动控制
- 可以通过
gc.collect()
手动触发垃圾回收 - 可以通过
gc.disable()
和gc.enable()
禁用或启用垃圾回收 循环垃圾收集器虽然解决了循环引用问题, 但是需要额外的计算资源, 可能会影响性能。
- 可以通过
分代回收(Generational Collection)
Python 的垃圾回收器还采用了分代回收策略, 基于对象的存活时间将对象分为不同的代(Generation)
- 分代
- 新创建的对象属于第
0
代 - 如果对象在依次垃圾回收后仍然存活, 则会被移动到下一代
- Python默认分3代(
0
,1
,2
)
- 新创建的对象属于第
- 回收频率
- 第
0
代的对象回收频率最高 - 第
2
代的对象回收频率最低
- 第
每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收容器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。新生的对象更有可能被垃圾回收,而存活更久的对象也有更高的概率继续存活。这样做提高了垃圾回收的效率, 因为大部分对象的生命周期较短。
弱引用(Weak References)
Python 提供了 weakref
模块, 用于创建弱引用。弱引用不会增加对象的引用计数, 因此不会阻止对象被回收。
- 使用场景
- 缓存
- 避免循环引用
python
import weakref
class Myclass:
pass
obj = Myclass() # obj引用Myclass实例, Myclass实例的引用计数是1
weak_obj = weakref.ref(obj) # 创建对obj的弱引用, 此时Myclass实例的引用计数仍然是1
print(weak_obj()) # 输出: <__main__.Myclass object at 0x7fb28a4ee640>
del obj # 显式删除对Myclass实例的引用, Myclass的引用实例为0, 被Python回收
print(weak_obj()) # 输出: None
手动管理内存
虽然 Python 有自动垃圾回收机制, 但在某些情况下, 开发者可能需要手动管理内存:
- 使用
del
删除不再需要的对象 - 使用
gc.collect()
手动触发垃圾回收 - 使用
with
语句管理资源(如文件、网络连接等)
(暂时结束, 持续更新)