当前位置:

首页 > 编程开发 > 如何理解和优化Python的垃圾回收机制?

如何理解和优化Python的垃圾回收机制?

得益于Python的自动垃圾回收机制,在Python中创建对象时无须手动释放。这对开发者非常友好,让开发者无须关注低层内存管理。但如果对其垃圾回收机制不了解,很多时候写出的Python代码会非常低效。垃圾回收算法有很多,主要有:引用计数、标记-清除、分代收集等。在python中,垃圾回收算法以引用计数为主,标记-清除和分代收集两种机制为辅。1引用计数1.1引用计数算法原理引用计数原理比较简单:每个对象有一个整型的引用计数属性。用于记录对象被引用的次数。例如对象A,如果有一个对象引用了A,则A的引用计数+1

本文目录

    得益于 Python 的自动垃圾回收机制,在 Python 中创建对象时无须手动释放。这对开发者非常友好,让开发者无须关注低层内存管理。但如果对其垃圾回收机制不了解,很多时候写出的 Python 代码会非常低效。

    垃圾回收算法有很多,主要有: 引用计数 、 标记-清除 、 分代收集 等。

    在 python 中,垃圾回收算法以 引用计数 为主, 标记-清除 和 分代收集 两种机制为辅。

    1 引用计数

    1.1 引用计数算法原理

    引用计数原理比较简单:

    每个对象有一个整型的引用计数属性。用于记录对象被引用的次数。例如对象 A ,如果有一个对象引用了 A ,则 A 的引用计数 +1 。当引用删除时, A 的引用计数 -1 。当 A 的引用计数为0时,即表示对象 A 不可能再被使用,直接回收。

    在 Python 中,可以通过 sys 模块的 getrefcount 函数获取指定对象的引用计数器的值,我们以实际例子来看。

    import sys
    
    class A():
        def __init__(self):
            pass
            
    a = A()
    print(sys.getrefcount(a))

    运行上面代码,可以得到输出结果为 2 。

    1.2 计数器增减条件

    上面我们看到,创建一个 A 对象,并将对象赋值给 a 变量后,对象的引用计数器值为 2 。那么什么时候计数器会 +1 ,什么时候计数器会 -1 呢?

    1.2.1 引用计数+1的条件
    A()
    a=A()
    func(a)
    arr=[a,a]
    1.2.2 引用计数-1的条件

    对象被显式销毁,如 del a 。变量重新赋予新的对象,例如 a=0 。对象离开它的作用域,如 func 函数执行完毕时, func 函数中的局部变量(全局变量不会)。

    对象所在的容器被销毁,或从容器中删除对象。

    1.2.3 代码实战

    为了更好的理解计数器的增减,我们运行实际代码,一目了然。

    import sys
     
    class A():
    
        def __init__(self):
            pass
     
    print("创建对象 0 + 1 =", sys.getrefcount(A()))
    
    a = A()
    print("创建对象并赋值 0 + 2 =", sys.getrefcount(a))
    
    b = a
    c = a
    print("赋给2个变量 2 + 2 =", sys.getrefcount(a))
    
    b = None
    print("变量重新赋值 4 - 1 =", sys.getrefcount(a))
    
    del c
    print("del对象 3 - 1 =", sys.getrefcount(a))
    
    d = [a, a, a]
    print("3次加入列表 2 + 3 =", sys.getrefcount(a))
    
    
    def func(c):
        print('传入函数 1 + 2 = ', sys.getrefcount(c))
    func(A())

    输出结果如下:

    创建对象 0 + 1 = 1
    创建对象并赋值 0 + 2 = 2
    赋给2个变量 2 + 2 = 4
    变量重新赋值 4 - 1 = 3
    del对象 3 - 1 = 2
    3次加入列表 2 + 3 = 5
    传入函数 1 + 2 =  3

    1.3 引用计数的优点与缺点

    1.3.1 引用计数优点
    • 高效、逻辑简单,只需根据规则对计数器做加减法。

    • 实时性。一旦对象的计数器为零,就说明对象永远不可能再被用到,无须等待特定时机,直接释放内存。

    1.3.2 引用计数缺点

    需要为对象分配引用计数空间,增大了内存消耗。

    当需要释放的对象比较大时,如字典对象,需要对引用的所有对象循环嵌套调用,可能耗时比较长。

    循环引用。 这是引用计数的致命伤,引用计数对此是无解的,因此必须要使用其它的垃圾回收算法对其进行补充。

    如何理解和优化Python的垃圾回收机制?

    2 标记-清除

    上一小节提到,引用计数算法无法解决循环引用问题,循环引用的对象会导致大家的计数器永远都不会等于 0 ,带来无法回收的问题。

    标记-清除 算法主要用于潜在的循环引用问题,该算法分为2步:

    1. 标记阶段。将所有的对象看成图的节点,根据对象的引用关系构造图结构。从图的根节点遍历所有的对象,所有访问到的对象被打上标记,表明对象是“可达”的。

    2. 清除阶段。遍历所有对象,如果发现某个对象没有标记为“可达”,则就回收。

    以具体代码示例说明:

    class A():
        def __init__(self):
            self.obj = None
     
    def func():
        a = A()
        b = A()
        c = A()
        d = A()
    
        a.obj = b
        b.obj = a
        return [c, d]
    
    e = func()

    上面代码中,a和b相互引用,e引用了c和d。整个引用关系如下图所示

    如何理解和优化Python的垃圾回收机制?

    如果采用引用计数器算法,那么a和b两个对象将无法被回收。而采用标记清除法,从根节点(即e对象)开始遍历,c、d、e三个对象都会被标记为 可达 ,而a和b无法被标记。因此a和b会被回收。

    这是读者可能会有疑问,为什么确定根节点是e,而不会是a、b、c、d呢?这里就有讲究了,什么样的对象会被看成是根节点呢?一般而言,根节点的选取包括(但不限于)如下几种:

    • 当前栈帧中的本地变量表中引用的对象,如各个线程被调用的方法堆栈中使用到的参数、 局部变量、 临时变量等。

    • 全局静态变量

    • ...

    3 分代收集

    3.1 分代收集原理

    在执行垃圾回收过程中,程序会被暂停,即 stop-the-world 。这里很好理解:你妈妈在打扫房间的时候,肯定不允许你在房间内到处丢垃圾,要不然永远也无法打扫干净。

    为了减少程序的暂停时间,采用 分代回收 ( Generational Collection )降低垃圾收集耗时。

    分代回收基于这样的法则:

    1. 接大部分的对象生命周期短,大部分对象都是朝生夕灭。

    2. 经历越多次数的垃圾收集且活下来的对象,说明该对象越不可能是垃圾,应该越少去收集。

    Python 中,对象一共有3种世代: G0 , G1 , G2 。

    1. 对象刚创建时为 G0 。

    2. 如果在一轮 GC 扫描中存活下来,则移至 G1 ,处于 G1 的对象被扫描次数会减少。

    3. 如果再次在扫描中活下来,则进入 G2 ,处于 G1 的对象被扫描次数将会更少。

    3.2 触发GC时机

    当某世代中分配的对象数量与被释放的对象之差达到某个阈值的时,将触发对该代的扫描。当某世代触发扫描时,比该世代年轻的世代也会触发扫描。

    那么这个阈值是多少呢?我们可以通过代码查看或者修改,示例代码如下

    import gc
    threshold = gc.get_threshold()
    print("各世代的阈值:", threshold)
    
    # 设置各世代阈值
    # gc.set_threshold(threshold0[, threshold1[, threshold2]])
    gc.set_threshold(800, 20, 20)

    输出结果如下:

    各世代的阈值: (700, 10, 10)
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。