Python内存管理技巧,一篇文章告诉你内存优化的本质!

大家好,我是花姐!💡 还记得你第一次写 Python 代码的时候吗?那种随意创建变量、毫无节制地 new 一个又一个对象的快感,简直让人沉迷!😂 可是,当代码运行变慢、内存占用飙升时,你才会意识到:

"诶?怎么 Python 还会吃这么多内存?!"

今天,我们就来聊聊 Python 的内存管理,帮你写出更高效、优化内存占用的 Python 代码!🎯


1. Python 的内存管理机制

Python 内部使用 引用计数(Reference Counting)垃圾回收(Garbage Collection, GC) 机制来管理内存。

1.1 引用计数

每个对象都有一个"计数器",记录它被多少个变量引用。一旦引用计数归零,Python 立刻释放这个对象的内存。

python 复制代码
import sys

a = []  # 创建一个列表对象
print(sys.getrefcount(a))  # 输出 2(因为 sys.getrefcount() 也会额外增加一次引用)

b = a  # 变量 b 也指向同一个列表
print(sys.getrefcount(a))  # 输出 3

del a
print(sys.getrefcount(b))  # 输出 2

del b  # 引用计数归零,内存被释放

💡 注意sys.getrefcount() 的结果比你想象的多 1,因为它本身也会创建一个临时引用!

1.2 垃圾回收(GC)

Python 采用 分代回收 ,对象被分成三代:新生代、中生代、老生代。垃圾回收主要针对循环引用的情况。

python 复制代码
import gc

class A:
    def __init__(self):
        self.ref = None

obj1 = A()
obj2 = A()
obj1.ref = obj2
obj2.ref = obj1  # 形成循环引用

del obj1, obj2  # 引用计数没有归零,Python 需要 GC 来清理

gc.collect()  # 手动触发垃圾回收

2. Python 内存优化技巧

2.1 使用 __slots__限制对象属性

默认情况下,Python 的对象使用 动态字典(__dict__ 存储属性,占用大量内存。如果你的类属性是固定的,可以用 __slots__ 优化,之前花姐在其它文章中提到过。

python 复制代码
class NormalClass:
    pass

class SlotClass:
    __slots__ = ['name', 'age']  # 仅允许 name 和 age 两个属性

obj1 = NormalClass()
obj1.name = "花姐"
obj1.age = 18
obj1.gender = "女"  # 允许动态添加新属性

obj2 = SlotClass()
obj2.name = "花姐"
obj2.age = 18
# obj2.gender = "女"  # ❌ AttributeError: 'SlotClass' object has no attribute 'gender'

__slots__ 会让 Python 不再为对象创建 __dict__,从而减少内存占用。

2.2 避免不必要的临时变量

Python 解释器会缓存一些常见的对象,例如 小整数-5256 在 Python 3.9 及以前的版本),以及部分 短字符串

但在 Python 3.10+ 之后,整数的缓存范围 可能更大,具体行为依赖于 Python 实现。

python 复制代码
# 可能被缓存(具体范围取决于 Python 版本)
a = 256
b = 256
print(a is b)  # True

# 可能不被缓存
a = 257
b = 257
print(a is b)  # 3.9 以前通常 False,3.10+ 可能 True

结论 :Python 会缓存小整数,但具体范围视 Python 版本而定,不建议过分依赖此特性!

2.3 使用生成器代替列表

如果你只需要 逐个获取数据,而不是一次性加载所有数据 ,请用 生成器 代替列表。

python 复制代码
# 占用大量内存的方式
nums = [i for i in range(10**6)]

# 更优的方式(惰性加载)
def num_generator():
    for i in range(10**6):
        yield i

gen = num_generator()

为什么? 生成器不会一次性把所有数据存入内存,而是每次 yield 一个值,这样可以大幅降低内存占用!🎉

2.4 使用 array 代替列表存储大量数值

如果你需要存储大量的数值,使用 array 模块比 list 更节省内存。

python 复制代码
import array

# 创建一个存储 int 类型的数组,比列表更节省内存
arr = array.array('i', range(10**6))

2.5 使用 deque 代替列表进行队列操作

collections.deque 具有更高效的 头部插入和删除 操作,比 listpop(0)insert(0, x) 更优。

python 复制代码
from collections import deque

dq = deque(range(10**6))
dq.appendleft(-1)  # O(1) 复杂度

# 而 list.insert(0, -1) 是 O(n),在大规模数据下性能差距明显

3. 释放不用的内存

3.1 手动释放变量

Python 采用 自动垃圾回收 ,但如果你想主动释放大对象,建议使用 del调用 gc.collect()

python 复制代码
import gc

data = [i for i in range(10**6)]
del data  # 删除变量
gc.collect()  # 强制触发垃圾回收

在大数据处理中,这个方法可以 显著减少内存占用


总结

  1. Python 采用 引用计数 + 垃圾回收 来管理内存。
  2. 使用 __slots__ 可以节省对象的 属性存储空间
  3. 避免不必要的临时变量 ,Python 会缓存小整数 ,但范围 依赖 Python 版本
  4. 用生成器替代列表,节省内存!
  5. array 代替 list 存储大量数值,提高内存效率。
  6. deque 代替 list 进行队列操作,提高性能。
  7. 手动释放大对象 ,使用 del + gc.collect() 及时清理。

希望今天的内容对你有帮助!

相关推荐
程序视点15 分钟前
FDM下载神器:免费多线程下载工具,速度90+M/S,完美替代1DM!
windows·后端
东风西巷16 分钟前
猫眼浏览器:简约安全的 Chrome 内核增强版浏览器
前端·chrome·安全·电脑·软件需求
太阳伞下的阿呆16 分钟前
npm安装下载慢问题
前端·npm·node.js
happycode70036 分钟前
数据库迁移实践
后端
pe7er41 分钟前
Tauri 应用打包与签名简易指南
前端
前端搬砖仔噜啦噜啦嘞42 分钟前
Cursor AI 编辑器入门教程和实战
前端·架构
AI 嗯啦44 分钟前
机器学习 —— 决策树
python·机器学习
Livingbody44 分钟前
【ERNIEKit】基于ERNIE4.5-0.3B大模型微调的心理咨询师大模型全流程
后端
Jimmy1 小时前
TypeScript 泛型:2025 年终极指南
前端·javascript·typescript
睿思达DBA_WGX1 小时前
Python 程序设计讲义(36):字符串的处理方法——去除字符串头尾字符:strip() 方法、lstrip() 方法与rstrip() 方法
开发语言·python