Python中内存管理机制与优化技巧分享
目录
- 1. python 的内存管理机制
- 1.1 引用计数
- 1.2 垃圾回收(GC)
- 2. Python 内存优化技巧
- 2.1 使用 __slots__限制对象属性
- 2.2 避免不必要的临时变量
- 2.3 使用生成器代替列表
- 2.4 使用 array 代替列表存储大量数值
- 2.5 使用 deque 代替列表进行队列操作
- 3. 释放不用的内存
- 总结
还记得你第一次写 Python 代码的时候吗?那种随意创建变量、毫无节制地 new 一个又一个对象的快感,简直让人沉迷!可是,当代码运行变慢、内存占用飙升时,你才会意识到:
“诶?怎么 Python 还会吃这么多内存?!”
今天,我们就来聊聊 Python 的内存管理,帮你写出更高效、优化内存占用的 Python 代码!
1. Python 的内存管理机制
Python 内部使编程客栈用 引用计数(Reference Counting) 和 垃圾回收(Garbage Collection, GC) 机制来管理内存。
1.1 引用计数
每个对象都有一个“计数器”,记录它被多少个变量引用。一旦引用计数归零,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.get编程客栈refcount()
的结果比你想象的多 1,因为它本身也会创建一个临时引用!
1.2 垃圾回收(GC)
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__
优化,之前花姐在其它文章中提到过。
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 解释器会缓存一些常见的对象,例如 小整数(-5
到 256
在 Python 3.9 及以前的版本),以及部分 短字符串。
但在 Python 3.10+ 之后,整数的缓存范围 可能更大,具体行为依赖于 Python 实现。
# 可能被缓存(具体范围取决于 Phttp://www.devze.comython 版本) 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 使用生成器代替列表
如果你只需要 逐个获取数据,而不是一次性加载所有数据,请用 生成器 代替列表。
# 占用大量内存的方式 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
更节省内存。
import array # 创建一个存储 int 类型的数组,比列表更节省内存 arr = array.array('i', range(10**6))
2.5 使用 deque 代替列表进行队列操作
collections.deque
具有更高效的 头部插入和删除 操作,比 list
的 pop(0)
和 insert(0, x)
更优。
from collections import deque dq = deque(range(10**6)) dq.appendleft(-1) # O(1) 复杂度 # 而 list.insert(0, -1) 是 O(n),在大规模数据下性能差距明显
3. 释放不用的内存
手动释放变量
Python 采用 自动垃圾回收,但如果你想主动释放大对象,建议使用 del
并 调用 gc.collect()
。
import gc data = [i for i in range(10**6)] del data # 删除变量 gc.collect() # 强制触发垃圾回收
在大数据处理中,这个方法可以 显著减少内存占用!
总结
Python 采用 引用计数 + 垃圾回收 来管理内存。
使用 __slots__ 可以节省对象的 属性存储空间。
避免不必要的临时变量,Python 会缓存小整数,但范围 依赖 Python 版本。
用生成器替代列表,节省内存!
用 array 代替 list 存储大量数值,提高内存效率。
用 deque 代替 list 进行队列操作,提高性能。
手动释放大对象,使用 del + gc.collect() 及时清理。
到此这篇关于Python中内存管理机制与优化技巧分享的文章就介绍到这了,更多相关Python内存管理www.devze.com与优化内android容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论