Skip to content

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 语句管理资源(如文件、网络连接等)



(暂时结束, 持续更新)

Released under the MIT License.