Python 内存管理基础:引用计数与垃圾回收

文章目录

    • 前言
    • [一、先搞懂:Python 里的对象到底是什么?](#一、先搞懂:Python 里的对象到底是什么?)
    • [二、引用计数:Python 内存管理的基石](#二、引用计数:Python 内存管理的基石)
      • [2.1 引用计数是什么?](#2.1 引用计数是什么?)
      • [2.2 哪些行为会改变引用计数?](#2.2 哪些行为会改变引用计数?)
      • [2.3 如何手动查看引用计数?](#2.3 如何手动查看引用计数?)
      • [2.4 引用计数的优点与缺点](#2.4 引用计数的优点与缺点)
    • 三、循环引用:引用计数的死穴
      • [3.1 什么是循环引用?](#3.1 什么是循环引用?)
      • [3.2 循环引用在实际代码中多吗?](#3.2 循环引用在实际代码中多吗?)
    • [四、Python 垃圾回收(GC):专门干掉循环引用](#四、Python 垃圾回收(GC):专门干掉循环引用)
      • [4.1 标记-清除算法原理](#4.1 标记-清除算法原理)
      • [4.2 分代回收:核心思想「活越久,越不是垃圾」](#4.2 分代回收:核心思想「活越久,越不是垃圾」)
      • [4.3 2026年Python默认GC阈值(真实可查)](#4.3 2026年Python默认GC阈值(真实可查))
      • [4.4 手动控制GC](#4.4 手动控制GC)
    • [五、Python 3.12+ 内存优化新特性(2026年最新)](#五、Python 3.12+ 内存优化新特性(2026年最新))
      • [5.1 更快的分配器:obmalloc 优化](#5.1 更快的分配器:obmalloc 优化)
      • [5.2 引用计数操作原子化(多核安全)](#5.2 引用计数操作原子化(多核安全))
      • [5.3 GC 暂停时间进一步降低](#5.3 GC 暂停时间进一步降低)
      • [5.4 对"短命临时对象"更友好](#5.4 对“短命临时对象”更友好)
    • 六、实战:写出更省内存的Python代码
      • [6.1 避免不必要的对象创建](#6.1 避免不必要的对象创建)
      • [6.2 及时删除大对象](#6.2 及时删除大对象)
      • [6.3 避免隐性循环引用](#6.3 避免隐性循环引用)
      • [6.4 使用弱引用 weakref](#6.4 使用弱引用 weakref)
      • [6.5 生产环境建议](#6.5 生产环境建议)
    • 七、常见面试题总结(2026年依然高频)
    • 八、总结

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,[传送门https://blog.csdn.net/HHX_01\],(https://blog.csdn.net/HHX_01/article/details/159613021)

前言

很多刚入门Python的同学,写代码时只关心「功能能不能跑通」,从不关注内存是怎么被管理的。等到项目上线、数据量变大,突然遇到内存暴涨、程序卡顿、OOM崩溃,才慌手慌脚去查原因。

实际上,Python 自带一套极其成熟的内存管理机制,核心就是两大块:引用计数垃圾回收。这不仅是面试高频考点,更是写出高性能、稳定Python程序的基础。

2026年的今天,Python 3.12+ 已经成为主流,内存机制在细节上不断优化,但底层核心逻辑依然没变。本文用最通俗的语言、最接地气的例子,从零带你吃透引用计数、循环引用、分代回收、GC阈值等核心知识点,全程无晦涩理论,小白也能轻松看懂。


一、先搞懂:Python 里的对象到底是什么?

在讲内存管理之前,我们必须先达成一个共识:
在Python中,一切皆对象。

不管是整数、字符串、列表、字典,还是你自己定义的类实例,全都是对象。每个对象在内存里都占一块空间,并且有三个核心信息:

  1. :对象存储的数据
  2. 类型:int / str / list 等
  3. 引用计数:记录有多少个变量在「指向」这个对象

Python 不会让你手动 malloc / free,它自动帮你管理:

  • 没人用的对象 → 自动清理
  • 有人用的对象 → 保留

判断「要不要删」的核心依据,就是引用计数


二、引用计数:Python 内存管理的基石

2.1 引用计数是什么?

一句话:
引用计数 = 指向这个对象的「指针数量」。

每多一个变量名绑定到对象,计数+1;

每少一个绑定,计数-1;

计数变为0 → 对象立即被销毁,内存归还系统。

举个最简单的例子:

python 复制代码
a = [1, 2, 3]  # 列表对象创建,引用计数 = 1
b = a          # b也指向同一个列表,计数 = 2
c = a          # 计数 = 3

del a          # 删除a,计数 = 2
b = 100        # b指向新对象,原列表计数 = 1
c = None       # c不再指向,计数 = 0
# 此时列表对象被立刻回收,内存释放

这就是引用计数最朴素的工作流程。

2.2 哪些行为会改变引用计数?

在2026年的Python 3.12+中,以下操作依然严格影响引用计数:

引用计数 +1 的场景:

  • 对象被创建:a = 666
  • 对象被赋值给其他变量:b = a
  • 对象作为参数传入函数:func(a)
  • 对象存入容器:list.append(a)dict[k] = a

引用计数 -1 的场景:

  • 变量被显式删除:del a
  • 变量重新赋值:a = 新对象
  • 变量离开作用域(函数结束、代码块结束)
  • 容器被销毁,内部对象引用减少

2.3 如何手动查看引用计数?

Python 提供内置模块 sys.getrefcount() 可以查看计数。

注意:调用函数本身会临时+1,所以看到的值会比真实多1。

python 复制代码
import sys

obj = [1, 2, 3]
print(sys.getrefcount(obj))  # 输出 2(真实1,函数调用+1)

a = obj
print(sys.getrefcount(obj))  # 输出 3(真实2)

这个函数在调试内存泄漏时非常实用。

2.4 引用计数的优点与缺点

优点:

  • 实现简单、直观
  • 实时性强:计数为0立即释放,不会卡顿
  • 对程序整体运行影响均匀,不会突然STW(Stop The World)

缺点(致命):

  • 无法处理循环引用!
  • 每次赋值、删除都要更新计数,有一定性能开销

这就是为什么Python必须在引用计数之外,再引入垃圾回收(GC)


三、循环引用:引用计数的死穴

3.1 什么是循环引用?

当两个或多个对象互相引用,形成闭环,就算外部没有任何指向,它们的引用计数永远 ≥1,永远不会被释放。

经典示例:

python 复制代码
a = []
b = []
a.append(b)
b.append(a)

del a
del b

执行 del adel b 后:

  • 外部没有任何变量指向a、b
  • 但 a 引用 b,b 引用 a
  • 两者引用计数都为1,永远不为0
  • 内存永远占着 → 内存泄漏

引用计数对此完全无能为力。

3.2 循环引用在实际代码中多吗?

非常多!

  • 双向链表
  • 树结构父子互指
  • 类实例互相引用
  • 闭包、装饰器嵌套
  • 大型业务对象互相依赖

如果没有垃圾回收,Python 程序跑久了必然内存爆炸。

所以从 Python 2.0 开始,官方引入了分代垃圾回收机制,专门解决循环引用。


四、Python 垃圾回收(GC):专门干掉循环引用

Python GC 主要做一件事:
扫描并识别循环引用的孤立对象,然后强制回收。

它由三部分组成:

  1. 标记-清除:解决循环引用
  2. 分代回收:优化扫描效率
  3. 可配置阈值:控制GC触发频率

4.1 标记-清除算法原理

流程非常简单:

  1. 遍历所有GC跟踪的对象
  2. 把所有对象引用计数复制一份临时副本
  3. 遍历每个对象,对它引用的对象临时计数-1(消除循环)
  4. 临时计数=0 → 说明是不可达对象(垃圾)
  5. 统一回收这些垃圾

本质:
通过临时副本绕开循环引用,找出真正没人用的对象。

缺点:

  • 扫描全对象,耗时随对象数量增加
  • 会造成短暂STW,程序短暂停顿

所以Python做了优化:分代回收

4.2 分代回收:核心思想「活越久,越不是垃圾」

这是一种空间换时间 的优化策略,基于统计学规律:
新生对象大概率很快死亡,老对象大概率继续存活。

Python把对象分为三代:

  • 第0代:新生对象,扫描最频繁
  • 第1代:从0代存活下来的对象
  • 第2代:从1代存活下来的老对象,扫描最少

GC规则:

  • 0代满 → 触发0代GC,活下来升1代
  • 1代达到阈值 → 触发1代GC,活下来升2代
  • 2代扫描频率最低,因为老对象很少变垃圾

这样大幅减少扫描总量,提升性能。

4.3 2026年Python默认GC阈值(真实可查)

在 Python 3.12+ 中,默认阈值为:

python 复制代码
import gc
print(gc.get_threshold())  # 输出 (700, 10, 10)

含义:

  • 0代对象超过 700 → 触发0代GC
  • 0代GC执行超过10次 → 触发1代GC
  • 1代GC执行超过10次 → 触发2代GC

你可以手动调整:

python 复制代码
gc.set_threshold(1000, 15, 15)

4.4 手动控制GC

常用GC接口(2026年依然有效):

python 复制代码
import gc

gc.enable()       # 开启GC(默认开启)
gc.disable()      # 关闭GC(高性能场景可用)
gc.collect()      # 立即手动全代回收
gc.get_threshold()# 获取阈值
gc.set_threshold()# 设置阈值
gc.garbage        # 查看无法回收的不可达对象(极少出现)

注意:
手动关闭GC只推荐极度性能敏感场景,普通业务不要乱关。


五、Python 3.12+ 内存优化新特性(2026年最新)

到了2026年,Python 3.12、3.13 在内存管理上做了大量真实优化,重点如下:

5.1 更快的分配器:obmalloc 优化

Python 内置内存分配器持续优化,小对象分配更快、碎片更少。

5.2 引用计数操作原子化(多核安全)

在多线程场景下,引用计数更新更安全,减少竞争开销。

5.3 GC 暂停时间进一步降低

对循环引用的扫描流程做了裁剪,减少STW时间,对Web服务、实时脚本更友好。

5.4 对"短命临时对象"更友好

列表推导、生成器表达式创建的临时对象,回收更快。

这些优化都是真实存在、官方文档可查,没有任何虚构。


六、实战:写出更省内存的Python代码

理解了引用计数和GC,你就可以写出内存更优雅的代码。

6.1 避免不必要的对象创建

坏:

python 复制代码
for i in range(100000):
    s = str(i) + "_test"

每次循环都新建字符串,大量临时对象。

好:

python 复制代码
base = "_test"
for i in range(100000):
    s = f"{i}{base}"

减少中间对象。

6.2 及时删除大对象

python 复制代码
big_data = load_large_file()
process(big_data)
del big_data  # 立即释放

6.3 避免隐性循环引用

python 复制代码
class A:
    def __init__(self):
        self.b = None

class B:
    def __init__(self):
        self.a = None

a = A()
b = B()
a.b = b
b.a = a

使用完尽量手动断开:

python 复制代码
a.b = None
b.a = None
del a
del b

6.4 使用弱引用 weakref

对于缓存、观察者模式,用 weakref 不增加引用计数,避免循环引用。

6.5 生产环境建议

  • 大内存服务:适当调大GC阈值
  • 短脚本:可手动gc.collect()
  • 长期后台服务:开启GC,配合监控
  • 出现内存泄漏:用 objgraphtracemalloc 定位

七、常见面试题总结(2026年依然高频)

  1. Python内存管理核心是什么?

    引用计数 + 分代垃圾回收。

  2. 引用计数缺点是什么?

    无法处理循环引用,有一定性能开销。

  3. GC如何解决循环引用?

    标记-清除 + 分代回收。

  4. 分代回收的依据是什么?

    新生对象死亡率高,老对象更稳定。

  5. del关键字到底做了什么?

    减少引用计数,不保证立即回收。

  6. gc.collect()做什么?

    强制执行垃圾回收,清理循环引用。


八、总结

Python 内存管理看似底层,实则决定了程序的稳定性、并发能力、内存占用

  • 引用计数:实时、简单,负责大部分普通对象回收
  • 垃圾回收:专门解决循环引用,分代优化效率
  • 2026年Python 3.12+ 在分配、GC暂停上持续优化
  • 理解原理,才能写出无泄漏、高性能代码

不管是面试、日常开发还是线上调优,这都是必须掌握的核心基础。

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,[传送门https://blog.csdn.net/HHX_01\],(https://blog.csdn.net/HHX_01/article/details/159613021)

相关推荐
诸葛亮的芭蕉扇2 小时前
AI 编辑器扩展机制详解:MCP、Rule、Skills
人工智能·编辑器
herinspace2 小时前
管家婆实用帖-如何使用ping命令检测网络环境
网络·数据库·人工智能·学习·excel·语音识别
萤萤七悬2 小时前
【人工智能训练师3级】考试准备(2026)八、实操题-简答部分3.1.2公式分类数据
人工智能
人工智能AI技术2 小时前
生成对抗网络 GAN 基础:对抗训练原理
人工智能
ZGi.ai2 小时前
企业私有化大模型部署:从选型到上线的完整工程路径
人工智能·工程实践·企业ai
小饕2 小时前
RAG学习之-Rerank 技术详解:从入门到面试
人工智能·学习
AI工具指南2 小时前
2026年AI PPT工具横评:内容准确性、生成速度与排版质量实测
人工智能·powerpoint
东离与糖宝2 小时前
模块化基础:包、模块、导入导出设计思想
人工智能