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() 及时清理。

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

相关推荐
江畔柳前堤2 分钟前
PyQt学习系列11-综合项目:多语言文件管理器
开发语言·网络·python·学习·django·pyqt
斯~内克5 分钟前
Vite + Vue 工程中,为什么需要关注 `postcss.config.ts`?
前端·vue.js·postcss
蜗牛快跑21310 分钟前
使用 Cursor 从 0 到 1 开发一个全栈 chatbox 项目
前端·人工智能·ai·ai编程
眠修10 分钟前
Python 实现web请求与响应
开发语言·python
鸡鸭扣17 分钟前
leetcode hot100:十四、解题思路大全:真·大全!
数据结构·python·算法·leetcode·力扣·笔试
Python涛哥40 分钟前
前端流行框架Vue3教程:24.动态组件
前端·javascript·vue.js
钢铁男儿1 小时前
C# 深入理解类(析构函数和this关键字)
java·python·c#
折戟不必沉沙1 小时前
python使用pycharm和conda 设置默认使用清华镜像
python·pycharm·conda
(・Д・)ノ1 小时前
python打卡day34
开发语言·python
劲爽小猴头1 小时前
HTML5快速入门-表单&实用标签
前端·html·html5